/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   VIDEO模块  
  Function List:     
  History:
    <huangzhendi -- 2014-09-26>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#include "videoPriv.h"
#include "videoIsp.h"
#include "VideoIn.h"
// #include "vdo_OsdMenuInterface.h"
#include "rk628dDrv.h"
#include "StreamComposeMgr.h"
#include "lt6911cDrv.h"

/*=============================================================================
                               Macro Definition
 =============================================================================*/
#define VI_WIDTH 1920
#define VI_HEIGHT 1080

#define HDMIIN_WIDTH 1920
#define HDMIIN_HEIGHT 1080

/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/


/*=============================================================================
                             Extern Variables                                  
=============================================================================*/


/*=============================================================================
                             Local Variables                                  
 =============================================================================*/
static int connectStatus_s = 0; 
static LT6911C_cmdArgs_t lt6911cArgs_s;


/*=============================================================================
                             Function Definition                                  
 =============================================================================*/ 

#define FONTSIZE 32
#define ACS32_FILEPATH	"/user/data/osd/asc32"
#define HZK32_FILEPATH	"/user/data/osd/hzk32"
#define TTF_FILEPATH	"/user/data/osd/siyuan.ttf"


/*******************************************************************************
  Function:     VI_AddRef
  Description:  增加接口引用
  Input:        - pThiz: 视频编码接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_AddRef(struct VideoInput *pThiz)
{
    VI_ctl_t *pViCtl;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&videoCtl_g.viMutex);

    pViCtl->refCount++;
    
    pthread_mutex_unlock(&videoCtl_g.viMutex);
    
    return 0;
}

/*******************************************************************************
  Function:     VI_Release
  Description:  释放接口
  Input:        - pThiz: 视频编码接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_Release(struct VideoInput *pThiz)
{
    int ret = 0;
    VI_ctl_t *pViCtl;
    
    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }
    
    pthread_mutex_lock(&videoCtl_g.viMutex);
    
    if (pViCtl->refCount > 1)
    {
        pViCtl->refCount--;
        goto unlock_mutex;
    }

    videoCtl_g.pViCtl[pViCtl->viChn] = NULL;
    free(pViCtl);
    
unlock_mutex: 
    pthread_mutex_unlock(&videoCtl_g.viMutex);
    return ret;
}

/*******************************************************************************
  Function:     VI_GetCaps
  Description:  得到视频输入支持的特性。
  Input:        - pThiz: 视频输入接口指针
  Output:       - enable: 指向视频输入特性结构VideoInCaps的指针。
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetCaps(struct VideoInput *pThiz, VideoInCaps *pCaps)
{
    VIDEO_picSize_t picSize;
    int ret = 0; 

    memset(pCaps, 0x00, sizeof(VideoInCaps));
    
    VIDEO_GetPicSize(videoCtl_g.standard, 
                     videoCtl_g.maxResolution, 
                     &picSize,
                     0);

    pCaps->maxWidth = picSize.u32Width;
    pCaps->maxHeight = picSize.u32Height;       

    //视频输入最高负载码流kbps
    pCaps->ladenBitrate        = 4096;

    /// 水平像素叠加功能掩码，从最低到最高每位依次对应是否支持2,3,4...像素叠加
    pCaps->horizontalBinning    = 0;
    /// 垂直像素叠加功能掩码，从最低到最高每位依次对应是否支持2,3,4...像素叠加
    pCaps->verticalBinning    = 0;

    ///是否支持画面缩小,不包括binning模式
    pCaps->downScaling        = 0;

    ///是否支持画面放大
    pCaps->upScaling        = 0;

    ///曝光速度控制等级数
    pCaps->exposure        = 0;

    /// 是否支持背光补偿，，0表示不支持背光补偿，1支持，2-支持区域调节    
    pCaps->backlight        = 0;

    /// 是否支持日夜颜色自动转换，0-不支持，1-支持 
    pCaps->dayNightColor = 1;  

    ///是否支持图像镜像
    pCaps->mirror            = 1;

    ///是否支持图像翻转
    pCaps->flip                = 1;

    /// 是否支持白平衡，0-不支持，1-支持自动白平衡，2-也支持预置白平衡，
    /// 3-也支持自定义白平衡
    /// 先设置为3 web 页面上的选项先全部打开
    pCaps->whiteBalance        = 3;

    ///是否支持增益控制
    pCaps->gain            = 1;

    ///是否支持自动增益
    pCaps->gainAuto        =1;

    ///自多支持的区域覆盖个数
    pCaps->coverCount        =4;

    /// 是否支持区域覆盖 0-不支持，1-支持实时的区域覆盖， 即设置区域时
    /// 速度较快，可以实时调用， 2-支持非实时的区域覆盖，即设置区域时速度较慢，
    /// 只能在用户确定区域后调用。  
    pCaps->coverType        =1;

    ///支持最多的标题叠加个数
    pCaps->titleCount        =2;    // 通道标题  时间标题

    ///光圈能力掩码
    pCaps->irisMask                = (uchar)videoCtl_g.lenInfo.irisOpType;
	
    ///是否支持红外补偿 0 -不支持 1 -支持
    pCaps->infraRed            =1;

    ///是否支持颜色调节
    pCaps->setcolor            =1;

    /// 前端支持输出分辨率数目，具体分辨率数值使用getFormatCaps接口函数获取。
    /// 如果值为0，表示前端格式采用编码的格式(比如分辨率、帧率)，不需要限制。
    pCaps->formatCount         = 1;
    
    /// 是否支持分辨率顺时针或逆时针旋转90°，0-不支持，1-支持
    pCaps->rotate90            = videoCtl_g.isRotate;

    /// 支持的视频输入信号格式掩码，\see VideoSignalFormat
    pCaps->signalFormatMask        = videoSignalFormat720p;

    /// 通道同步是指由于前端AD的限制，
    /// 同一个芯片上的某个码流(主码流或辅码流)的多个
    /// 通道的分辨率必须一致。
    pCaps->syncChipChannels        = 0;
    
    /// 通道所在的芯片号
    pCaps->chipID = 0;
    
    /// 是否支持多套选项，0-不支持，1-支持白天夜晚两套选项
    pCaps->multiOptions        = 0;
    
    /// 是否支持抓图单独曝光
    pCaps->snapshotExposure     = 0;

    /// 是否支持带时间上下限的自动曝光，0-不支持，1-支持
    pCaps->limitedAutoExposure    = 0;

    /// 是否支持用户自定义手动曝光时间，0-不支持，1-支持
    pCaps->customManualExposure    = 0;

    /// 是否支持外部同步信号输入，0-不支持，1-支持
    pCaps->externalSyncInput    =    0;

    /// 是否支持参考电压设置，0-不支持，1-支持
    pCaps->refrenceLevel        =0;
    
    /// 是否支持闪光灯调节，0-不支持，1-支持
    pCaps->flashAdjust = 0;

    /// 是否支持ircut控制，0-不支持，1-支持
    pCaps->ircut = 1;
    
    /// 支持的最小曝光时间
    pCaps->minExposureTime = 0;

    /// 支持的最大曝光时间
    pCaps->maxExposureTime = 0;

    /// 支持的宽动态模式，0-不支持, 1-数字宽动态，2-真实宽动态。 
    pCaps->wideDynamicRange = videoCtl_g.wideDynamicRange;   

    /// 是否支持双快门，0-不支持，1-支持双快门全帧率，2-支持双快门半帧率，
    /// 3-支持双快门全帧率和双快门半帧率
    pCaps->doubleExposure = 0;

    /// 抓拍支持的最小曝光时间
    pCaps->minExposureTime1 = 0;

    /// 抓拍支持的最大曝光时间
    pCaps->maxExposureTime1 = 0;

    /// 2A编译时间，对应的UTC(1970-1-1 00:00:00)秒数
    pCaps->utc = 0;
    
    /// 2Asvn版本号
    pCaps->version = 0;

    /// 最大测光区域个数
    pCaps->meteringRegionCount = 0;

    ///是否支持自动相位，0-不支持，1-支持
    pCaps->autoSyncPhase = 0;

    /// 是否支持亮度补偿，如根据车牌亮度调整图像曝光，0-不支持，1-支持
    pCaps->brightnessCompensation = 0;
    
    /// 是否支持强光抑制，0-不支持，1-支持
    pCaps->glareInhibition = 0;
    
    /// 支持自动曝光模式掩码，详见VideoExposureMode
    /// 只有手动和自动
    pCaps->exposureMode = (1 << videoExposureMode60HZFlickerless) 
                          | (1 << videoExposureMode50HZFlickerless)
                          | (1 << videoExposureModeDefaultAuto);

    /// 是否支持电动变焦，0-不支持，1-支持   
	pCaps->focusMask = (uchar)videoCtl_g.lenInfo.afOpType;
	if (pCaps->focusMask)
	{
		pCaps->electricFocus = 1;
	}
	else
	{
		pCaps->electricFocus = 0;
	}

    /// 是否支持聚焦峰值计算，0-不支持，1-支持
    pCaps->afPeak = 0;
    
    /// 视频最小曝光时间小数部分，范围：1~99，单位：0.01毫秒
    pCaps->minExposureTimeFrac = 1;
    
    /// 视频最大曝光时间小数部分，范围：1~99，单位：0.01毫秒
    pCaps->maxExposureTimeFrac = 1;
    
    /// 图片最小曝光时间小数部分，范围：1~99，单位：0.01毫秒
    pCaps->minExposureTime1Frac = 1;
    
    /// 图片最大曝光时间小数部分，范围：1~99，单位：0.01毫秒
    pCaps->maxExposureTime1Frac = 1;
    
    /// 支持的锐度可调节最大等级，支持 5，100
    pCaps->eeModeRange = 255;// 100;

    /// 是否支持3D降噪，0-不支持，1-支持软件3D降噪，2-FPGA硬件3D降噪
    pCaps->tridimDenoise = 1;
    
    /// 是否支持鱼眼算法，0-不支持，1-支持
    pCaps->fishEye = videoCtl_g.isFisheye;

    /// 抓拍是否支持帧匹配模式，0-不支持，1-支持
    pCaps->frameMatch = 0;
    
    /// 是否支持3D降噪参数设置，0-不支持，1-支持,tridimDenoise为1时才有效
    pCaps->tridimDenoiseDetails = 1;
    
    /// 3D降噪支持类型，0-支持视频和图片，1-只支持视频，2-只支持图片，
    /// tridimDenoise不为0时才有效
    pCaps->tridimDenoiseMode = 1;

    /// 最大图片占空比
    pCaps->maxPicOccupy = 0;
    
    /// 支持解交错,0-不支持，1-支持
    pCaps->deInterlace = 0;

    /// 支持最大减光晕区域个数，0表示不支持
    pCaps->maxKillHaloRegion = 0;
    
    /// 支持通过外部IO来控制ICR切换
    if (videoCtl_g.dayNightSwitchMask & (1<<videoDayNightSwitchPhotoresistor)
        || videoCtl_g.dayNightSwitchMask & (1<<videoDayNightSwitchIO))
    {
        pCaps->dayNightColorIO = 1;
    }
    else
    {
        pCaps->dayNightColorIO = 0;
    }
    
    /// 是否支持同步对焦
    pCaps->syncFocus = 0;

    /// 支持最小减光晕等级
    pCaps->minKillHaloLevel = 0;
        
    /// 支持最大减光晕等级
    pCaps->maxKillHaloLevel = 0; 

    /// 是否支持智能红外灯smartIr
    pCaps->smartIrMode = videoCtl_g.smartIr;
    pCaps->smartIrMask = videoCtl_g.smartIrMask;

    /// 是否支持畸变矫正
    if (videoCtl_g.ldc == NO_LDC)
    {
        pCaps->ldc = 0;
    }
    else
    {
        pCaps->ldc = 1;
    }

    /// 日夜切换方式掩码
    pCaps->dayNightSwitchMask = videoCtl_g.dayNightSwitchMask;

	/// 是否支持动态修改真实宽动态，0-不支持，1-支持 （不支持时切换需要重启设备）
    pCaps->dynRealWdr = 1;

	if (videoCtl_g.viVpssMode)
	{
		pCaps->dis = 0;
	}
	else
	{
    	pCaps->dis = 1;
	}
    
    return ret;
}


/*******************************************************************************
  Function:     VI_EnableAutoIris
  Description: 使能自动光圈
  Input:        - pThiz: 视频输入接口指针
  Output:       - enable: 使能开关，1-使能，0-禁止
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_EnableAutoIris(struct VideoInput *pThiz, int enable)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pEnableAutoIris(pVideoIsp, enable);
        if (ret)
        {
            LOG_PrintError("Isp set iris fail!\n");
            return -1;
        }
    }
    
    return 0;
}


/*******************************************************************************
  Function:     VI_SetColor
  Description:  获取曝光速度列表.
  Input:        - pThiz: 视频输入接口指针
                - standard: 视频制式，取VideoStandard类型的值。
  Output:       - speeds: 速度数组，每一种速度用一个float表示，从0递增以曝光等级
                - num: 表示speeds速度数组所包含的元素个数
            作为下标，表示对应等级的具体曝光速度。数组长度必须足以放下所有等级
            的速度值，等级数参见VI_GetCaps接口。正数表示曝光时间，毫秒为单位。
            比如2000表示曝光时间为2秒，是慢速曝光；100表示曝光时间为100ms，
            是快速曝光；0表示自动曝光，在数组中下标一定为0(自动曝光等级)。
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/ 
static int VI_GetExposureSpeeds(struct VideoInput *pThiz, 
                                VideoStandard standard, 
                                float *pSpeeds,
                                int *pNum)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pGetExposureSpeeds(pVideoIsp, standard, pNum, pSpeeds);
        if (ret)
        {
            LOG_PrintError("isp get exposure speed failed!\n");
            return -1;
        }
    }
    
    return 0;
}

/*******************************************************************************
  Function:     VI_GetFormatCaps
  Description:  获取前端支持的格式列表，
                应用层必须从支持的列表中选择一项作为setFormat接口的输入参数。
  Input:        - pThiz: 视频输入接口指针的指针
                - standard: 视频制式，取VideoStandard类型的值。
  Output:       - pFormats: 格式结构VideoInFormat数组，数组长度必须足以放下所有
                            支持的格式列表。支持的格式数目用
                            VideoInCaps::formatCount表示。
                            VideoInFormat中的width、height、fps表示前端对应的分
                            辨率下的最大帧率。VideoInFormat中的window对应分辨率
                            的视野限制，如果4个值都非0，表示固定视野； 如果4个
                            值都为0，表示支持电子云台，视野由应用程序任意控制；
                            4个值都为0也可以表示底层不关心视野区域，并忽略
                            setFormat接口调用中的VideoInFormat结构该成员。
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetFormatCaps(struct VideoInput *pThiz, 
                            VideoStandard standard, 
                            VideoInFormat *pFormats)
{ 
    VIDEO_picSize_t picSize;
    VIDEO_resolution_t resolution;
    int i;
	float fps;
	    
    switch (standard)
    {
        case videoStandardPAL:
            i = 0;
            
            resolution = videoCtl_g.resolution;
            if (videoCtl_g.maxFps)
            {
                fps = videoCtl_g.maxFps;
            }
            else
            {
                fps = 25;
            }
            
            VIDEO_GetPicSize(videoStandardPAL, 
                             resolution, 
                             &picSize,
                             0);
        
            pFormats[i].width = picSize.u32Width;
            pFormats[i].height = picSize.u32Height;
            pFormats[i].fps = fps;
            break;
            
        case videoStandardNTSC:
            i = 0;
            
            resolution = videoCtl_g.resolution;
            if (videoCtl_g.maxFps)
            {
                fps = videoCtl_g.maxFps;
            }
            else
            {
                fps = 30;
            }
            
            VIDEO_GetPicSize(videoStandardNTSC, 
                             resolution, 
                             &picSize,
                             0);
        
            pFormats[i].width = picSize.u32Width;
            pFormats[i].height = picSize.u32Height;
            pFormats[i].fps = fps;
            break;
            
        default:
            LOG_PrintWarn("standard %d is invalid!\n", standard);
            return -1;
    }
    
    return 0;
}


/*******************************************************************************
  Function:     VI_GetFormatCapsEx
  Description:  获取前端支持的格式列表，
                应用层必须从支持的列表中选择一项作为setFormat接口的输入参数。
  Input:        - pThiz: 视频输入接口指针的指针
	            - pFormatOptions 获取前端分辨率的特征属性，
	                             参见VideoInFormatOptions类型。
  Output:       - pFormats: 格式结构VideoInFormat数组，数组长度必须足以放下所有
                            支持的格式列表。支持的格式数目用
                            VideoInCaps::formatCount表示。
                            VideoInFormat中的width、height、fps表示前端对应的分
                            辨率下的最大帧率。VideoInFormat中的window对应分辨率
                            的视野限制，如果4个值都非0，表示固定视野； 如果4个
                            值都为0，表示支持电子云台，视野由应用程序任意控制；
                            4个值都为0也可以表示底层不关心视野区域，并忽略
                            setFormat接口调用中的VideoInFormat结构该成员。
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetFormatCapsEx(struct VideoInput *pThiz, 
                            const VideoInFormatOptions *pFormatOptions, 
                            VideoInFormat *pFormats)
{ 
    VIDEO_picSize_t picSize;
    VIDEO_resolution_t resolution;
    int i;
	float fps;
	    
    switch (pFormatOptions->standard)
    {
        case videoStandardPAL:
            i = 0;
            
            resolution = videoCtl_g.resolution;
            if (videoCtl_g.maxFps)
            {
                fps = videoCtl_g.maxFps;
            }
            else
            {
                fps = 25;
            }
            
            VIDEO_GetPicSize(videoStandardPAL, 
                             resolution, 
                             &picSize,
                             0);
        
            pFormats[i].width = picSize.u32Width;
            pFormats[i].height = picSize.u32Height;
            pFormats[i].fps = fps;
            break;
            
        case videoStandardNTSC:
            i = 0;
            resolution = videoCtl_g.resolution;
           
            if (videoCtl_g.maxFps)
            {
                fps = videoCtl_g.maxFps;
            }
            else
            {
                fps = 30;
            }
            
            VIDEO_GetPicSize(videoStandardNTSC, 
                             resolution, 
                             &picSize,
                             0);
        
            pFormats[i].width = picSize.u32Width;
            pFormats[i].height = picSize.u32Height;
            pFormats[i].fps = fps;
            break;
            
        default:
            LOG_PrintWarn("standard %d is invalid!\n", pFormatOptions->standard);
            return -1;
    }
    
    return 0;
}


/*******************************************************************************
  Function:     VI_SetColor
  Description:  设置视频输入的颜色参数。
  Input:        - pThiz: 视频输入接口指针的指针
                - pColor: 指向颜色结构VideoColor的指针。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetColor(struct VideoInput *pThiz, VideoColor *pColor)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;
    VI_ctl_t *pViCtl = (VI_ctl_t *)pThiz->priv;

    if( (NULL == pViCtl) || (NULL == pThiz) || (NULL == pColor) )
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

    if(0 == pViCtl->viChn)
    {
        pVideoIsp = videoCtl_g.pVideoIsp;
    }
    else if(1 == pViCtl->viChn)
    {
        pVideoIsp = videoCtl_g.pVideoSecIsp;
    }

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetColor(pVideoIsp, pColor);
        if (ret)
        {
            LOG_PrintError("Isp set color fail!!\n");
            return -1;
        }
    }
    
    return 0;
}

static int VI_GetColor(struct VideoInput *pThiz, VideoColor *pColor)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;
    
    if (pVideoIsp)
    {
        ret = pVideoIsp->pGetColor(pVideoIsp, pColor);
        if (ret)
        {
            LOG_PrintError("Isp set color fail!!\n");
            return -1;
        }
    }
    
    return 0;
}

/*******************************************************************************
  Function:     VI_SetPreviewOptions
  Description:  设置视频输入选项。
  Input:        - pThiz: 视频输入接口指针的指针
                - pViOption: 指向视频选项结构VideoInOption的指针。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetOptions(struct VideoInput *pThiz, VideoInOptions *pViOption)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;
    
    pVideoIsp = videoCtl_g.pVideoIsp;

    if (!pThiz || !pViOption)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

    if (pVideoIsp)
    {
        ret = pVideoIsp->pGetOption(pVideoIsp, pViOption);
        if (ret)
        {
            LOG_PrintError("Isp set color fail!!\n");
            return -1;
        }
    }

    return 0;
}

/*******************************************************************************
  Function:     VI_SetPreviewOptions
  Description:  设置视频输入选项。
  Input:        - pThiz: 视频输入接口指针的指针
                - pViOption: 指向视频选项结构VideoInOption的指针。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetOptions(struct VideoInput *pThiz, VideoInOptions *pViOption)
{
    int result;
    int ret = 0, i = 0;
    int vpssChn, vpssGrp = 0;
    VIDEOISP_ctl_t *pVideoIsp;

    if (!pThiz || !pViOption)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

    int num = 2;
    for(i = 0; i < num; ++i)
    {
        pVideoIsp = NULL;
        
        if(i == 0)
        {
            pVideoIsp = videoCtl_g.pVideoIsp;
        }
        else
        {
            pVideoIsp = videoCtl_g.pVideoSecIsp;
        }

        if (!pVideoIsp)
        {
            LOG_PrintError("pVideoIsp is null!\n");
            return -1;
        }
        
        pthread_mutex_lock(&videoCtl_g.viMutex);

        //if (videoCtl_g.mirrorCfg != pViOption->mirror)
        {
            //videoCtl_g.mirrorCfg = pViOption->mirror;
            videoCtl_g.mirror = (pViOption->mirror == 0) ? (1) : (0);
            videoCtl_g.flip = (pViOption->flip == 0) ? (1) : (0);

            printf("[%s][%d] [%s],pViOption->mirror=%d,pViOption->flip=%d,videoCtl_g.mirror=%d, videoCtl_g.flip=%d\n",
                    __FILE__,__LINE__,__FUNCTION__,pViOption->mirror,pViOption->flip, videoCtl_g.mirror,videoCtl_g.flip); 
            
            if (pVideoIsp)
            {
                result = pVideoIsp->pSetMirrorFlip(pVideoIsp, videoCtl_g.mirror, videoCtl_g.flip);
                if (result)
                {
                    LOG_PrintError("Isp set color fail!!\n");
                    ret = -1;	
        			goto unlock;
                }
            }
        }

        if (pVideoIsp)
        {
            result = pVideoIsp->pSetOption(pVideoIsp, pViOption);
            if (result)
            {
                LOG_PrintError("Isp set color fail!!\n");
                ret = -1;	
    			goto unlock;
            }
        }

        pthread_mutex_unlock(&videoCtl_g.viMutex);
    }

    if(i == num)
    {
        return 0; 
    }

unlock:
	pthread_mutex_unlock(&videoCtl_g.viMutex);
    return ret;
#if 0
    int result=0, ret;
    int wdrEn=0, oldRotate;
    char key[8] = {0};
    ROTATION_E tmpRotate;
    int isResetCover = 0;
    char tmpMirror, tmpFlip;
    VideoInOptions videoInOptions;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (!pThiz || !pViOption)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.viMutex);

    memcpy(&videoInOptions, pViOption, sizeof(VideoInOptions));

    if (videoInOptions.mirror != videoCtl_g.mirror
        || videoInOptions.flip != videoCtl_g.flip
        || videoInOptions.rotate90 != videoCtl_g.rotate)
    {
        isResetCover = 1;
    }

    if (videoInOptions.rotate90)
    {
        tmpMirror = videoInOptions.mirror;
        tmpFlip= videoInOptions.flip;
        videoInOptions.mirror = tmpFlip;
        videoInOptions.flip = tmpMirror;
    }

    if (videoCtl_g.isRotate)
    {    
        switch (videoInOptions.rotate90)
        {
            case 0: tmpRotate = ROTATION_0;
                    break;
            case 1: tmpRotate = ROTATION_90;
                    break;   
            case 2: 
            case 3:
                    tmpRotate = ROTATION_270;
                    break;
            default:
                    LOG_PrintError("rotate90 %d is invalid!\n", 
                                    videoInOptions.rotate90);
                    result = -1;
                    goto unlock;
        }
        
        oldRotate = videoCtl_g.rotate;
        if (oldRotate != (int)tmpRotate)
        {
            videoCtl_g.rotate = (int)tmpRotate; 
        }
    }

	if (isResetCover)
	{
	    ret = DETECT_RecreateChn();
	    if (ret)
	    {
	        LOG_PrintError("Fail to recreate detect channel!\n");
	        result = -1;
	        goto unlock;
	    }
    }

    if (videoInOptions.wideDynamicRangeMode)
	{
		wdrEn = 1;
	}

	if (wdrEn != videoCtl_g.wdrEnable)
	{
        videoCtl_g.wdrEnable =  wdrEn;
		sprintf(key, "%d", wdrEn);
		SYS_IniKeySet(VIDEO_INI_CFG, "video", "wdrEnable", key);	
	}
    
    if (pVideoIsp)
    {         
        ret = pVideoIsp->pSetOption(pVideoIsp, &videoInOptions);
        if (ret)
        {
            LOG_PrintError("Isp set optione fail!!\n");
            result = -1;
            goto unlock;
        }
    }

    videoCtl_g.mirror = (unsigned int)videoInOptions.mirror;
    videoCtl_g.flip= (unsigned int)videoInOptions.flip;

    if (isResetCover)
    {
        int i;
        ENC_cover_t *pEncCover;
        
        for (i = 0; i < ENC_COVER_NUM; i++)
        {
            pEncCover = &videoCtl_g.encCovers[i];
            
            ret = ENC_ResetCover(&pEncCover->videoCover);
            if (ret)
            {
                LOG_PrintError("reset cover fail!!\n");
                result = -1;
                goto unlock;
            }
        }

		/* 镜像或翻转状态发生变化时，需要配置相应参数 */
        ANALYSER_PrivSetMirror();
    }
    
unlock:
    pthread_mutex_unlock(&videoCtl_g.viMutex);
    return result;
#endif
}


/*******************************************************************************
  Function:     VI_SetPreviewOptions
  Description:  设置视频输入预处理选项
  Input:        - pThiz: 视频输入接口指针的指针
                - pPrevOption: 视频输入预处理选项结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetPreviewOptions(struct VideoInput *pThiz, 
                             VideoInPreviewOptions *pPrevOption)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetPreviewOptions(pVideoIsp, pPrevOption);
        if (ret)
        {
            LOG_PrintError("Isp set preview option fail!\n");
            return -1;
        }
    }
    
    return 0;
}


/*******************************************************************************
  Function:     VI_SetStandard
  Description:  设置视频输入制式。
  Input:        - pThiz: 视频输入接口指针的指针
  Output:       - standard: 视频制式
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetStandard(struct VideoInput *pThiz, int standard)
{
	int ret = 0;
	char key[8] = {0};
    VIDEO_standard_t videoStandard;
	VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    pthread_mutex_lock(&videoCtl_g.viMutex);

    switch (standard)
    {
        case videoStandardPAL:
            videoStandard = VIDEO_STANDARD_PAL;
            break;
            
        case videoStandardNTSC:
            videoStandard = VIDEO_STANDARD_NTSC;
            break;
            
        default:
            LOG_PrintError("standard %d is invalid!\n", standard);
            ret = -1;
            goto unlock;
    }
    
    LOG_PrintInfo("videoStandard is %d!\n", videoStandard);

    //sprintf(key, "%d", videoStandard);
	//INI_KeySet(VIDEO_INI_CFG, "video", "standard", key);

	if (!videoCtl_g.ispStart)
	{
		/*ret = pVideoIsp->pFuncStart(pVideoIsp);
		if (ret)
		{
			LOG_PrintError("pVideoIsp->pFuncStart failed!\n");
			ret = -1;	
			goto unlock;
		}*/

		videoCtl_g.ispStart = 1;
	}

unlock:
	pthread_mutex_unlock(&videoCtl_g.viMutex);
    return ret;
}


/*******************************************************************************
  Function:     VI_SetFormat
  Description:  设置视频输入的视野，分辨率，帧率等格式
  Input:        - pThiz: 视频输入接口指针
                - pFormat: 视频输入格式结构指针。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetFormat(struct VideoInput *pThiz, VideoInFormat *pFormat)
{  
    return 0;
}


/*******************************************************************************
  Function:     VI_AdjustFocus
  Description:  聚焦调节，调节放大倍率和焦点
  Input:        - pThiz: 视频输入接口指针
                - focus: 相对焦点变化，归一化到-1~1
                - zoom: 相对变倍率，归一化到-1~1
  Output:       
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_AdjustFocus(struct VideoInput *pThiz, float focus, float zoom)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pAdjustFocus(pVideoIsp, focus, zoom);
        if (ret)
        {
            LOG_PrintError("isp adjust focus failed!\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_AdjustFocusContinuously
  Description:  聚焦调节，调节放大倍率和焦点
  Input:        - pThiz: 视频输入接口指针
                - focus: 相对焦点变化，归一化到-1~1
                - zoom: 相对变倍率，归一化到-1~1
  Output:       
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_AdjustFocusContinuously(struct VideoInput *pThiz, 
                                     float focus,
                                     float zoom)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pAdjustFocusContinuously(pVideoIsp, focus, zoom);
        if (ret)
        {
            LOG_PrintError("isp adjust focus continuously failed!\n");
            return -1;
        }
    }
    
    return 0;
} 


/*******************************************************************************
  Function:     VI_AdjustFocus
  Description:  手动调节光圈，如果自动光圈已经打开，手动调节无效
  Input:        - pThiz: 视频输入接口指针
                - open: 1-光圈扩大，0-光圈缩小
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_AdjustIris(struct VideoInput *pThiz, int open)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_AutoFocus
  Description:  自动聚焦，调节焦点至最佳位置
  Input:        - pThiz: 视频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_AutoFocus(struct VideoInput *pThiz)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pAutoFocus(pVideoIsp);
        if (ret)
        {
            LOG_PrintError("isp auto focus failed\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_GetFocusStatus
  Description:  取聚焦状态，辅助聚焦模式下有效
  Input:        - pThiz: 视频输入接口指针
  Output:       - pStatus: 聚焦算法选项结构体指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetFocusStatus(struct VideoInput *pThiz, 
                             VideoInFocusStatus *pStatus)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pGetFocusStatus(pVideoIsp, pStatus);
        if (ret)
        {
            LOG_PrintError("isp get focus status failed!\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetFocus
  Description:  设置聚焦参数
  Input:        - pThiz: 视频输入接口指针
  Output:       - pFocus: 聚焦参数结构体
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetFocus(struct VideoInput *pThiz, 
                          const VideoInFocus * pFocus)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetFocus(pVideoIsp, pFocus);
        if (ret)
        {
            LOG_PrintError("isp set focus failed!\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetZoom
  Description:  设置变倍参数
  Input:        - pThiz: 视频输入接口指针
  Output:       - pZoom: 聚焦参数结构体
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetZoom(struct VideoInput *pThiz, 
                       const VideoInZoom * pZoom)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetZoom(pVideoIsp, pZoom);
        if (ret)
        {
            LOG_PrintError("isp set zoom failed!\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_GetFocusStatus
  Description:  获取视频输入状态
  Input:        - pThiz: 视频输入接口指针
  Output:       - pStatus: 视频输入预处理状态结构体指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetStatus(struct VideoInput *pThiz, 
                        VideoInStatus *pStatus)
{ 
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pGetStatus(pVideoIsp, pStatus);
        if (ret)
        {
            LOG_PrintError("isp get status failed!\n");
            return -1;
        }
    }

    return 0;
} 

/*******************************************************************************
  Function:     VI_GetVideoInPutStatus
  Description:  获取视频采集输入状态
  Input:        - pThiz: 视频输入接口指针
  Output:       - pStatus: 采集输入状态结构体指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_GetVideoInPutStatus(struct VideoInput *pThiz, 
                                  VideoInPutStatus *pStatus)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_Reset
  Description:  重启前端。上层检测到前端异常时，重启前端，恢复异常。
  Input:        - pThiz: 视频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_Reset(struct VideoInput *pThiz)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SavePreviewOptions
  Description:  设备重启前通知底层保存预处理参数，
                该部分参数由底层维护应用程序不可见
  Input:        - pThiz: 视频输入接口指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SavePreviewOptions(struct VideoInput *pThiz)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetBackgroundColor
  Description:  设置视频输入的背景颜色，当没有视频信号时，应该显示为背景颜色。
  Input:        - pThiz: 视频输入接口指针
                - pColor: 要设置的颜色。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetBackgroundColor(struct VideoInput *pThiz, Color *pColor)
{
    return 0;
}

/*******************************************************************************
  Function:     VI_SetColorAdjustArea
  Description:  设置视频输入颜色调节区域
  Input:        - pThiz: 视频输入接口指针
                - number: 调节区域个数
                - pArea: 调节区域结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetColorAdjustArea(struct VideoInput *pThiz,
                                 int number,
                                 VideoInColorAdjustArea *pArea)
{
    return 0;
}


/*******************************************************************************
  Function:     VI_SetCover
  Description:  设置视频输入覆盖区域。
  Input:        - pThiz: 视频输入接口指针
                - pCover: 指向视频覆盖结构VideoCover的指针，
                          参数里的坐标是缩放前的坐标。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetCover(struct VideoInput *pThiz, VideoCover *pCover)
{
    int ret = 0;
    VI_ctl_t  *pViCtl = NULL;

    if (!pThiz || !pCover)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }


    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&pViCtl->viChnMutex);

    pViCtl->isCover = pCover->enable;

    pthread_mutex_unlock(&pViCtl->viChnMutex);

mutex_unlock:
    return ret;
} 

/*******************************************************************************
  Function:     VI_SetDenoise
  Description:  设置降噪参数
  Input:        - pThiz: 视频输入接口指针
                - pDenoise: 降噪参数结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetDenoise(struct VideoInput *pThiz, 
                         const VideoInDenoise *pDenoise)
{
    return 0;
} 


/*******************************************************************************
  Function:     VI_SetDenoiseParamsMaps
  Description:  设置降噪内部参数
  Input:        - pThiz: 视频输入接口指针
                - pDesc: 降噪参数数组描述
                - pCfgDataArr: 降噪参数数组
                - numbers: 降噪参数数组个数
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetDenoiseParamsMaps(struct VideoInput *pThiz, 
                                   const VideoInDenoiseParamsDesc *pDesc, 
                                   const VideoInDenoiseParams *pCfgDataArr, 
                                   int numbers)
{
    return 0;
} 


/*******************************************************************************
  Function:     VI_SetFocusMode
  Description:  设置聚焦模式
  Input:        - pThiz: 视频输入接口指针
                - mode: 聚焦模式，0-关闭，1-辅助，2-自动
                - pOptions: 聚焦算法选项结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetFocusMode(struct VideoInput *pThiz, 
                           int mode, 
                           VideoInFocusOptions *pOptions)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetFocusMode(pVideoIsp, mode, pOptions);
        if (ret)
        {
            LOG_PrintError("isp set focus mode failed!\n");
            return -1;
        }
    }
    
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetKillHalo
  Description:  设置减光晕参数
  Input:        - pThiz: 视频输入接口指针
                - pKillHallo: 减光晕参数数组
                - count: 减光晕参数数组个数	
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetKillHalo(struct VideoInput *pThiz, 
                          VideoInKillHalo *pKillHallo, 
                          int count)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetMeteringMode
  Description:  设置视频输入测光模式
  Input:        - pThiz: 视频输入接口指针
                - pMode: 视频输入测光结构体指针
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetMeteringMode(struct VideoInput *pThiz, 
                              VideoInMeteringMode *pMode)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetMode
  Description:  设置视频输入采集模式。
  Input:        - pThiz: 视频输入接口指针
                - mode: 视频输入采集模式
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetMode(struct VideoInput *pThiz, 
                      VideoInMode mode)
{
    return 0;
} 


/*******************************************************************************
  Function:     VI_SetMode
  Description:  设置视屏输入采集模式
  Input:        - pThiz: 视频输入接口指针
                - mode: 视屏输入采集模式,0表示普通模式，1表示直通模式
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetMonitorMode(struct VideoInput *pThiz, 
                             int mode)
{
    return 0;
}  

/*******************************************************************************
  Function:     VI_SetSensorOptions
  Description:  设置视频输入传感器参数。
  Input:        - pThiz: 视频输入接口指针
                - pOptions: 视频输入传感器参数
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetSensorOptions(struct VideoInput *pThiz, 
                               VideoInSensorOptions *pOptions)
{ 
    int ret = 0;
    unsigned int wdrEnable;
    VIDEO_picSize_t picSize;   
    VIDEO_resolution_t resolution; 

    if (!pThiz || !pOptions)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

    if (pOptions->count != 1)
    {
        LOG_PrintError("num of options > 1 not support!\n");
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.viMutex);

    if (pOptions->realWideDynamic)
    {
        wdrEnable = 1;
    }
    else
    {
        wdrEnable = 0;
    }

    if (wdrEnable != videoCtl_g.wdrEnable)
    {
    	LOG_PrintError("wdrEnable %d != videoCtl_g.wdrEnable %d!\n", 
    				   wdrEnable, videoCtl_g.wdrEnable);
		ret = -1;
    	goto unclock;
    }

    picSize.u32Width = pOptions->options[0].width;
    picSize.u32Height = pOptions->options[0].height;

    ret = VIDEO_GetResolution(&picSize, 0, VIDEO_STANDARD_PAL, &resolution);
    if (ret)
    {
        LOG_PrintError("VI_JudgeResolution failed!\n");
        ret = -1;
        goto unclock;
    }

    if (resolution != videoCtl_g.resolution)
    {
    	LOG_PrintError("resolution %d != videoCtl_g.resolution %d!\n", 
    				   resolution, videoCtl_g.resolution);
		ret = -1;
    	goto unclock;
    }

unclock:
    pthread_mutex_unlock(&videoCtl_g.viMutex); 
    return ret;
} 


/*******************************************************************************
  Function:     VI_SetSensorType
  Description:  设置视频输入传感器型号。
  Input:        - pThiz: 视频输入接口指针
                - pType: 视频输入传感器型号字符串，如"Dahua","Hitachi"等等
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetSensorType(struct VideoInput *pThiz, 
                            const char *pType)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetSyncPhase
  Description:  设置外同步相位控制参数
  Input:        - pThiz: 视频输入接口指针
                - pSyncPhase: 外同步相位控制参数数组	
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetSyncPhase(struct VideoInput *pThiz, 
                           VideoInSyncPhase *pSyncPhase)
{
    return 0;
}

/*******************************************************************************
  Function:     VI_SetTitle
  Description:  设置外同步相位控制参数
  Input:        - pThiz: 视频输入接口指针
                - pTitle: 指向标题结构VideoTitle的指针，
                          参数里的坐标是缩放后的坐标。
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetOsdTitle(struct VideoInput *pThiz, VideoTitle *pTitle)
{
    return 0;
//     int s32Ret=0, result;
//     OSD_REGION_ID_E enRegionId = 0;
//     ENC_title_t *pEncTitle;
//     VideoTitle *pOldTitle;
//     BITMAP_S stBitmap = {0};
//     int s32FontSize;
//     int bpp = 0, oldbpp = 0;
//     int enOsdMirror = 0;

//     VI_ctl_t *pViCtl = NULL;

//     pViCtl = (VI_ctl_t *)pThiz->priv;
//     if (!pViCtl)
//     {
//         LOG_PrintError("VideoEncoder isn't initialized\n");
//         return -1;
//     }

//     bpp         = pTitle->bpp & 0x0f;
//     enOsdMirror = pTitle->bpp & 0x10;

//     if (pTitle->index > ENC_TITLE_NUM)
//     {
//         LOG_PrintError("OSD title index (%d) is out of range\n",
//                        pTitle->index);
//         return -1;
//     }

//     if (pTitle->enable)
//     {
//         if ((0 != bpp) && (1 != bpp) && (2 != bpp) && (3 != bpp) && (4 != bpp))
//         {
//             LOG_PrintError("OSD title bpp (%d) is not supported\n",
//                           bpp);
//             return -1;
//         }

//         if (   pTitle->width  <= 0
//             || pTitle->height <= 0
//             || pTitle->x      < 0 
//             || pTitle->y      < 0)
//         {
//             LOG_PrintError("OSD title %d invalid paramenters!\n", pTitle->index);
//             return -1;
//         }
//     }

//     //LOG_PrintInfo("pTitle->index:%d\n", pTitle->index);

//     pEncTitle = &pViCtl->encTitles[(int)pTitle->index];
//     pOldTitle = &pViCtl->videoTitle;
//     oldbpp    = pOldTitle->bpp & 0x0f;

//     enRegionId = pTitle->index;

//     pthread_mutex_lock(&pViCtl->viChnMutex);

//     if (pTitle->enable)
//     {        
//         if (pOldTitle->enable)
//         {
//             if ((2 == oldbpp) || (3 == oldbpp) || (4 == oldbpp))
//             {
//                 if (pViCtl->logoInfo.pBuffer)
//                 {
//                     BMP_Release(&pViCtl->logoInfo);
//                     pViCtl->logoInfo.pBuffer = NULL;
//                 }
//             }
//             else
//             {
//             }
//         }
//         if (2 == bpp)
//         {
//             s32FontSize = 32;//ENC_GetFontSize(pEncCtl);
//             ENC_StringToBmp(pTitle->data, &stBitmap, s32FontSize);
//             if(enOsdMirror)
//             {
//                 ENC_Rgb8888Mirror(&stBitmap);
//             }

//             ENC_Rgb8888ToYUV(&pViCtl->logoInfo, &stBitmap);
//         }
//         else if (3 == bpp)
//         {
//             unsigned char *pData = (unsigned char *)ENC_ReadBmpFile(pTitle->data);
//             if (!pData)
//             {
//                 LOG_PrintError("Fail to read bmp file!\n"); 
//                 s32Ret = -1;
//                 goto mutex_unlock;
//             }

//             if (pViCtl->logoInfo.pBuffer)
//             {
//                 BMP_Release(&pViCtl->logoInfo);
//                 pViCtl->logoInfo.pBuffer = NULL;
//             }

//             result = BMP_Format(&pViCtl->logoInfo, pData, BMP_TO_YUV420SP);
//             if (result)
//             {
//                 LOG_PrintError("Fail to format bmp!\n"); 
//                 free(pData);
//                 s32Ret = -1;
//                 goto mutex_unlock;
//             }
//         }
//         else if (4 == bpp)
//         {
//             if (pViCtl->logoInfo.pBuffer)
//             {
//                 BMP_Release(&pViCtl->logoInfo);
//                 pViCtl->logoInfo.pBuffer = NULL;
//             }
//             ENC_StringToNV12(pTitle->data, &pViCtl->logoInfo);//mirror todo
//         }
//         else
//         {
//             LOG_PrintError("bpp is invalid(%d)\n", bpp); 
//             s32Ret = -1;
//             goto mutex_unlock;
//         }
//      }
//      else 
//      {
//         if (pOldTitle->enable)
//         { 
//             if ((2 == oldbpp) || (3 == oldbpp) || (4 == oldbpp) )
//             {
//                 if (pViCtl->logoInfo.pBuffer)
//                 {
//                     BMP_Release(&pViCtl->logoInfo);
//                     pViCtl->logoInfo.pBuffer = NULL;
//                 }
//             }
//             else
//             {
//             }
//         }
//      }

//      memcpy(pOldTitle, pTitle, sizeof(VideoTitle));

// mutex_unlock:
//     if (NULL != stBitmap.pData)
//     {
//         free(stBitmap.pData);
//     }

//     pthread_mutex_unlock(&pViCtl->viChnMutex);

//     return s32Ret;
}

static IM_STATUS RGA_Clear_Rect(rga_buffer_t buf, RK_U32 width, RK_U32 height) 
{
    im_rect rect_all = {0, 0, width, height};
    IM_STATUS STATUS = imfill(buf, rect_all, 0x00000000);
    return STATUS;
}

int ENC_rgba8888PartCopy(Uint8* srcVir,Uint32 srcWid,Uint32 srcHei,
                                    Uint8* dstVir,Uint32 dstWid,Uint32 dstHei,
                                    Uint32 startX,Uint32 startY
                                    )
{
    int  iRet = 0;
    int  x =0;

    Uint8 * pDstVirRGBA = NULL;
    Uint8 * pSrcVirRGBA = NULL;
    int iStride = 4;

    //2、Fill camoff picture
    pSrcVirRGBA    = srcVir;

    pDstVirRGBA    = dstVir;

    for (x = 0; x < srcHei; x++)//copy y
    {
        Uint8 *pSrcDataY = pSrcVirRGBA + x * srcWid*iStride;
        Uint8 *pDstDataY = pDstVirRGBA + (dstWid*(startY + x) + startX)*iStride;

        memcpy(pDstDataY, pSrcDataY, srcWid*iStride);
    }

    return iRet;
}



static int VI_SetMenuOsd(struct VideoInput *pThiz, VideoTitle *pTitle)
{
    return 0;
    #if 0
    int s32Ret = 0;
    VI_ctl_t *pViCtl = NULL;

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoEncoder isn't initialized\n");
        return -1;
    }

    VDO_OSD_CMD_CONTROL emOsdCmd = VDO_OSD_CMD_BUTT;

    if(!strcmp(pTitle->data,OSD_INFO_MENU_UP))
    {
        emOsdCmd = VDO_OSD_CMD_UP;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_DOWN))
    {
        emOsdCmd = VDO_OSD_CMD_DOWN;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_LEFT))
    {
        emOsdCmd = VDO_OSD_CMD_LEFT;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_RIGHT))
    {
        emOsdCmd = VDO_OSD_CMD_RIGHT;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_CONFIRM))
    {
        emOsdCmd = VDO_OSD_CMD_CONFIRM;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_RETURN))
    {
        emOsdCmd = VDO_OSD_CMD_RETURN;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_THEME_ON))
    {
        emOsdCmd = VDO_OSD_CMD_MENU_ON;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_THEME_OFF))
    {
        emOsdCmd = VDO_OSD_CMD_MENU_OFF;
    }
    else if(!strcmp(pTitle->data,OSD_INFO_MENU_UPDATE_CONFIG))
    {
        emOsdCmd = VDO_OSD_CMD_MENU_UPDATE_CONFIG;
    }
    else
    {
        LOG_PrintError("menu cmd:%s no support \n",pTitle->data); 
    }

    /* open menu */
    if(VDO_OSD_CMD_MENU_ON == emOsdCmd)
    {
        int enOsdMirror = 0;
        enOsdMirror = pTitle->bpp & 0x10;

        LOG_PrintInfo("enOsdMirror:%d\n",enOsdMirror);
        videoCtl_g.iMenuMirrorAllLastStatus = enOsdMirror;
    }

    // vdo_osdMenu_cmdCtrl(emOsdCmd);

    VDO_OSD_IMAGE_INFO osdMenu;
    memset(&osdMenu,0x0,sizeof(VDO_OSD_IMAGE_INFO));
    vdo_osdMenu_getTitle(&osdMenu);

    int showEnable = 0;
    vdo_osdMenu_getStatus(&showEnable);

    int iSrcWid = 1920;
    int iSrcHei = 1080;
    int sync = 1;

    int iMenuMirror = videoCtl_g.iMenuMirrorAllLastStatus;

    if(0 == showEnable)
    {
        /* vi-thread no-use osd buffer,and clear osd-buffer-data */

        pthread_mutex_lock(  &pViCtl->viChnMutex);

        videoCtl_g.iMenuAllShow = 0;

        pthread_mutex_unlock(&pViCtl->viChnMutex);

    }
    else
    {
        /* mirror */
        BITMAP_S stDstBitMap;

        unsigned long long ts_start = vdo_get_time();

        if(iMenuMirror)
        {
            stDstBitMap.u32Width  = osdMenu.stImageRect.wid;
            stDstBitMap.u32Height = osdMenu.stImageRect.hei;
            stDstBitMap.pData     = malloc(stDstBitMap.u32Width * stDstBitMap.u32Height * 4);

            BITMAP_S stSrcBitMap;
            stSrcBitMap.pData     = osdMenu.pVir;
            stSrcBitMap.u32Width  = osdMenu.stImageRect.wid;
            stSrcBitMap.u32Height = osdMenu.stImageRect.hei;

            ENC_Rgb8888MirrorV2(&stDstBitMap,&stSrcBitMap);
        }
        else
        {
            stDstBitMap.pData     = osdMenu.pVir;
            stDstBitMap.u32Width  = osdMenu.stImageRect.wid;
            stDstBitMap.u32Height = osdMenu.stImageRect.hei;
        }
        unsigned long long ts_stop = vdo_get_time();

        //LOG_PrintInfo("use time:%lld\n", (ts_stop - ts_start) );

        pthread_mutex_lock(&pViCtl->viChnMutex);

        /* hmdi - 1080p*/
        VDO_OSD_IMAGE_INFO stOsdImage;
        memset(&stOsdImage,0x0,sizeof(VDO_OSD_IMAGE_INFO));
        s32Ret = ENC_AlgOsdGetCanvasAddr(0,&stOsdImage);
        if(s32Ret)
        {
            pthread_mutex_unlock(&pViCtl->viChnMutex);
            return -1;
        }

        /* clean and copy */
        MEDIA_BUFFER  pstBufferMb = NULL;
        pstBufferMb = (MEDIA_BUFFER)stOsdImage.reserved[0];
        rga_buffer_t buf = wrapbuffer_fd(RK_MPI_MB_GetFD(pstBufferMb), iSrcWid,
                       iSrcHei, RK_FORMAT_RGBA_8888);

        RGA_Clear_Rect(buf,iSrcWid,iSrcHei);

        Uint8* srcVir = stDstBitMap.pData;
        Uint32 srcWid = stDstBitMap.u32Width;
        Uint32 srcHei = stDstBitMap.u32Height;
        Uint8* dstVir = stOsdImage.pVir;
        Uint32 dstWid = iSrcWid;
        Uint32 dstHei = iSrcHei;
        Uint32 startX = 128;
        Uint32 startY = 128;

        if(iMenuMirror)
        {
            startX = iSrcWid - startX -srcWid;
        }

        startX = VIDEO_ALIGN_DOWN(startX, 4);
        startY = VIDEO_ALIGN_DOWN(startY, 4);

        RK_MPI_MB_BeginCPUAccess(pstBufferMb, RK_FALSE);

        ENC_rgba8888PartCopy(srcVir,srcWid,srcHei,dstVir,dstWid,dstHei,startX,startY);

        RK_MPI_MB_EndCPUAccess(pstBufferMb, RK_FALSE);

        videoCtl_g.iMenuAllShow = 1;

        pthread_mutex_unlock(&pViCtl->viChnMutex);
        if(iMenuMirror)
        {
            if(stDstBitMap.pData)
                free(stDstBitMap.pData);
        }
    }

    return s32Ret;
    #endif
}

static int VI_SetTitle(struct VideoInput *pThiz, VideoTitle *pTitle)
{
    return 0;
    #if 0
    int s32Ret = 0;
    int bpp = 0;
    VideoTitle stTitle;

    if (!pThiz || !pTitle)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    /* bpp:5,菜单栏 ，其他实现osd字幕 */
    bpp = pTitle->bpp & 0x0f;

    /* osd show --> menu show */
    stTitle.bpp    = 2;
    stTitle.index  = 2;
    stTitle.enable = 0;
    stTitle.x      = 16;
    stTitle.y      = 16;
    stTitle.width  = 1024;
    stTitle.height = 208;

    if(5 == bpp)
    {
        s32Ret = VI_SetOsdTitle(pThiz,&stTitle);
        s32Ret = VI_SetMenuOsd(pThiz,pTitle);
    }
    else
    {
        s32Ret = VI_SetOsdTitle(pThiz,pTitle);
    }

    return s32Ret;
    #endif
}


/*******************************************************************************
  Function:     VI_SetWidgetLine
  Description:  叠加视频辅助线
  Input:        - pThiz: 视频输入接口指针
                - pLine: 视频辅助线指针，参数里的坐标归一化到 [0,8192)
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetWidgetLine(struct VideoInput *pThiz, 
                            VideoWidgetLine *pLine)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_Snapshot
  Description:  触发视频输入抓拍，抓拍的原始帧数据将会加上mark标志，用来区分抓
                拍帧和普通帧，以及区分不同的抓拍帧。每次调用最多可以产生一个带
                标志帧的帧，也就是函数调用后紧接着的一帧。此函数可以设计成强制
                产生新的VD信号，立即从头开始采集新的一帧，将正在采集的帧丢弃，
                来保证触发响应的时效性。
  Input:        - pThiz: 视频输入接口指针
                - pSnapshot: 视频输入抓拍结构指针，是一个数组。
                - lanes: 一次需要抓拍的车道或通道个数
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_Snapshot(struct VideoInput *pThiz, 
                          VideoInSnapshot *pSnapshot, 
                          int lanes)
{
    return 0;
} 

/*******************************************************************************
  Function:     VI_SetSmartIr
  Description:  设置smartIr参数
  Input:        - pThiz: 视频输入接口指针
                - smartIrParam smartIr参数结构体 
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetSmartIr(struct VideoInput *pThiz, 
                         const VideoInSmartIrParams *pSmartIrPrm)
{

    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetSmartIr(pVideoIsp, pSmartIrPrm);
        if (ret)
        {
            LOG_PrintError("isp set focus failed!\n");
            return -1;
        }
    }

    return 0;
} 

/*******************************************************************************
  Function:     VI_SetAutoIris
  Description:  设置自动光圈参数
  Input:        - pThiz: 视频输入接口指针
                - pAutoIrisPrm: 自动光圈参数结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetAutoIris(struct VideoInput *pThiz, 
                         const VideoInAutoIrisParams *pAutoIrisPrm)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetAutoIris(pVideoIsp, pAutoIrisPrm);
        if (ret)
        {
            LOG_PrintError("isp set iris failed!\n");
            return -1;
        }
    }

    return 0;
} 


/*******************************************************************************
  Function:     VI_SetWhiteBalance
  Description:  设置白平衡参数
  Input:        - pThiz: 视频输入接口指针
                - pWhiteBalance: 白平衡参数结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetWhiteBalance(struct VideoInput *pThiz, 
                              const VideoInWhiteBalance *pWhiteBalance)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetWhiteBalance(pVideoIsp, pWhiteBalance);
        if (ret)
        {
            LOG_PrintError("isp set white balance failed!\n");
            return -1;
        }
    }

    return 0;
}


/*******************************************************************************
  Function:     VI_SetLdc
  Description:  设置畸变矫正参数
  Input:        - pThiz: 视频输入接口指针
                - pLdcPrm: 畸变矫正参数结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetLdc(struct VideoInput *pThiz, const VideoInLDCParams *pLdcPrm)
{
	return 0;
}


/*******************************************************************************
  Function:     VI_SetLdr
  Description:  设置感光值
  Input:        - pThiz: 视频输入接口指针
                - pLdrPrm: 感光值参数结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetLdr(struct VideoInput *pThiz, const VideoInLdrParams *pLdrPrm)
{
    int ret = 0, result;
    SYS_ldrPrm_t ldrPrm;

    if (!pThiz || !pLdrPrm)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }
    
    pthread_mutex_lock(&videoCtl_g.viMutex);

    ldrPrm.type = pLdrPrm->ldrType;
    ldrPrm.ldrValue.value = pLdrPrm->ldrValue.value;
    result = SYS_SetLdrValue(&ldrPrm);
    if (result)
    {
        LOG_PrintError("Fail to set ldr!\n");
        ret = -1; 
        goto unlock;
    }

unlock:
    pthread_mutex_unlock(&videoCtl_g.viMutex);
    return ret;
}

/*******************************************************************************
  Function:     VI_SetFec
  Description:  鱼眼参数设置
  Input:        - pThiz: 视频输入接口指针
                - pFecInfo: 鱼眼信息
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetFec(struct VideoInput *pThiz, VideoInFecInfo *pFecInfo)
{
	return 0;
}

/*******************************************************************************
  Function:     VI_CtrltPtz
  Description:  电子云台控制接口
  Input:        - pThiz: 视频输入接口指针
                - pFecInfo: 电子云台控制结构体
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_CtrltPtz(struct VideoInput *pThiz, VideoInPtzPrm *pPtzPrm)
{
	return 0;
}

/*******************************************************************************
  Function:     VI_GetFocusLimit
  Description:  获取聚焦限位列表
  Input:        - pThiz: 视频输入接口指针
  Output:       - ppVideoInput: 视频输入接口指针的指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/	
static int VI_GetFocusLimit(struct VideoInput *pThiz, uint *pDistance, int *pNum)
{
	if (!pThiz || !pDistance || !pNum)
    {
        LOG_PrintError("Parameter is null!\n");
        return -1;
    }

	*pNum = videoCtl_g.lenInfo.afLitNum;

    if (videoCtl_g.lenInfo.afLitNum)
    {
    	memcpy(pDistance, 
    		   videoCtl_g.lenInfo.afLit, 
    		   sizeof(uint)*videoCtl_g.lenInfo.afLitNum);
    }

    return 0;    
}


/*******************************************************************************
  Function:     VI_SetIris
  Description:  设置光圈参数
  Input:        - pThiz: 视频输入接口指针
  Output:       - irisPrm: 光圈参数结构体
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetIris(struct VideoInput *pThiz, const VideoInIrisParams *pIrisPrm)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp)
    {
        ret = pVideoIsp->pSetIris(pVideoIsp, pIrisPrm);
        if (ret)
        {
            LOG_PrintError("isp set iris failed!\n");
            return -1;
        }
    }

    return 0;
}


/*******************************************************************************
  Function:     VI_SetDis
  Description:  设置数字防抖参数
  Input:        - pThiz: 视频输入接口指针
  Output:       - pDisPrm: 数字防抖参数结构体
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetDis(struct VideoInput *pThiz, const VideoInDisPrm *pDisPrm)
{
    int ret;
    VIDEOISP_ctl_t *pVideoIsp;

    pVideoIsp = videoCtl_g.pVideoIsp;

    if (pVideoIsp && pVideoIsp->pSetDis)
    {
        ret = pVideoIsp->pSetDis(pVideoIsp, pDisPrm);
        if (ret)
        {
            LOG_PrintError("isp set dis failed!\n");
            return -1;
        }
    }

    return 0;
}



int VI_ImageCropRga(ENC_ImageRect_t stSrcRect,ENC_ImagePonit_t stDstPoint,ENC_ImageRect_t stDstRect,MEDIA_BUFFER stSrcMb,MEDIA_BUFFER stDstMb)
{
    int iRet   = 0;
    int status = 0;
    int iSync   = 1;

    im_rect stDstImRect = {0};
    im_rect stSrcImRect = {0};

    stSrcImRect.x      = stDstPoint.x;
    stSrcImRect.y      = stDstPoint.y;
    stSrcImRect.width  = stDstRect.wid;
    stSrcImRect.height = stDstRect.hei;

    int iSrcWid = stSrcRect.wid;
    int iSrcHei = stSrcRect.hei;

    int iDstWid = stDstRect.wid;
    int iDstHei = stDstRect.hei;

    rga_buffer_t stSrcRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stSrcMb), iSrcWid, iSrcHei, RK_FORMAT_YCbCr_420_SP);
    rga_buffer_t stDstRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stDstMb), iDstWid, iDstHei, RK_FORMAT_YCbCr_420_SP);

    status = imcheck(stSrcRgaBuffer, stDstRgaBuffer, stSrcImRect, stDstImRect, IM_CROP);
    if (IM_STATUS_NOERROR != status) 
    {
        LOG_PrintError("check error! %s", imStrError((IM_STATUS)status));
        return -1;
    }

    /* crop */
    status = imcrop(stSrcRgaBuffer, stDstRgaBuffer, stSrcImRect, iSync);
    if (status != IM_STATUS_SUCCESS)
    {
        LOG_PrintError("imcrop failed: %s\n", imStrError(status));
        return -1;
    }

    return iRet;
}

void ConvertUYVY422ToYUV420SP(const unsigned char* uyvy422, unsigned char* yuv420sp, int width, int height) 
{
    int frameSize = width * height * 2;
    int uvSize = width * height;
   

    unsigned long long  ts = vdo_get_time();
    
    int j = 0, k = 0;
    
    for (int h = 0 ; h < height; h++) 
    { 
        int pos = 2*h*width;
        for (int i = 0; i < 2 * width; i += 4, j += 2) 
        {
            
            unsigned char u1 = uyvy422[pos + i];
            unsigned char y1 = uyvy422[pos + i + 1];
            unsigned char v1 = uyvy422[pos + i + 2];
            unsigned char y2 = uyvy422[pos + i + 3];

            yuv420sp[j] = y1;
            yuv420sp[j + 1] = y2;

            if(h % 2 == 0)
            {
                yuv420sp[uvSize + k] = u1;
                yuv420sp[uvSize + k + 1] = v1;
                k += 2;
            }
        }
    }

    unsigned long long  runtime = vdo_get_time() - ts;
    //LOG_PrintWarn("Compose_DataComposeThd::dealPacket runtime=%llu\n", runtime);

    
}

int VI_ImageResizeRga(ENC_ImageRect_t stSrcRect,ENC_ImageRect_t stDstRect,MEDIA_BUFFER stSrcMb,MEDIA_BUFFER stDstMb, int srcFormat, int dstFormat)
{
    int iRet = 0;
    int iSync   = 1;
    int iStatus = 0;

    stSrcRect.wid = VIDEO_ALIGN_DOWN(stSrcRect.wid, 4);
    stSrcRect.hei = VIDEO_ALIGN_DOWN(stSrcRect.hei, 2);
    stSrcRect.wstride = VIDEO_ALIGN_DOWN(stSrcRect.wstride, 4);
    stSrcRect.hstride = VIDEO_ALIGN_DOWN(stSrcRect.hstride, 2);

    ///宽4字节对齐，高2字节对齐
    stDstRect.wid = VIDEO_ALIGN_DOWN(stDstRect.wid, 4);
    stDstRect.hei = VIDEO_ALIGN_DOWN(stDstRect.hei, 2);
    stDstRect.wstride = VIDEO_ALIGN_DOWN(stDstRect.wstride, 4);
    stDstRect.hstride = VIDEO_ALIGN_DOWN(stDstRect.hstride, 2);

    double  fx = ((double)stDstRect.wid)/stSrcRect.wid;
    double  fy = ((double)stDstRect.hei)/stSrcRect.hei;

    int iSrcWid = stSrcRect.wid;
    int iSrcHei = stSrcRect.hei;
    int iSrcWstride = stSrcRect.wstride;
    int iSrcHstride = stSrcRect.hstride;

    int iDstWid = stDstRect.wid;
    int iDstHei = stDstRect.hei;
    int iDstWstride = stDstRect.wstride;
    int iDstHstride = stDstRect.hstride;

    rga_buffer_t stSrcRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stSrcMb), iSrcWid, iSrcHei, srcFormat, iSrcWstride, iSrcHstride);
    rga_buffer_t stDstRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stDstMb), iDstWid, iDstHei,  dstFormat, iDstWstride, iDstHstride); 

    iStatus = imresize(stSrcRgaBuffer, stDstRgaBuffer, fx, fy, INTER_LINEAR, iSync);
    if (iStatus != IM_STATUS_SUCCESS)
    {
        LOG_PrintError("imresize failed: %s\n", imStrError(iStatus));
        return -1;
    }

    return iRet;
}

int VI_ImageResizeImprocess(ENC_ImageRect_t stSrcRect,ENC_ImageRect_t stDstRect,ENC_ImageRect_t stPatRect,im_rect stSrcCodt, im_rect stDstCodt, im_rect stPatCodt, MEDIA_BUFFER stSrcMb, MEDIA_BUFFER stDstMb, MEDIA_BUFFER stPatMb, int usage)
{
    int iRet = 0;
    int iStatus = 0;

    ///宽4字节对齐，高2字节对齐
    stSrcRect.wid = VIDEO_ALIGN_DOWN(stSrcRect.wid, 4);
    stSrcRect.hei = VIDEO_ALIGN_DOWN(stSrcRect.hei, 2);
    stSrcRect.wstride = VIDEO_ALIGN_DOWN(stSrcRect.wstride, 4);
    stSrcRect.hstride = VIDEO_ALIGN_DOWN(stSrcRect.hstride, 2);

    stSrcCodt.x = VIDEO_ALIGN_DOWN(stSrcCodt.x, 2);
    stSrcCodt.y = VIDEO_ALIGN_DOWN(stSrcCodt.y, 2);
    stSrcCodt.width = VIDEO_ALIGN_DOWN(stSrcCodt.width, 4);
    stSrcCodt.height = VIDEO_ALIGN_DOWN(stSrcCodt.height, 2);

    stDstCodt.x = VIDEO_ALIGN_DOWN(stDstCodt.x, 2);
    stDstCodt.y = VIDEO_ALIGN_DOWN(stDstCodt.y, 2);
    stDstCodt.width = VIDEO_ALIGN_DOWN(stDstCodt.width, 4);
    stDstCodt.height = VIDEO_ALIGN_DOWN(stDstCodt.height, 2);

    stPatCodt.x = VIDEO_ALIGN_DOWN(stPatCodt.x, 2);
    stPatCodt.y = VIDEO_ALIGN_DOWN(stPatCodt.y, 2);
    stPatCodt.width = VIDEO_ALIGN_DOWN(stPatCodt.width, 4);
    stPatCodt.height = VIDEO_ALIGN_DOWN(stPatCodt.height, 2);

    //printf("stSrcRect.wid=%d, stSrcRect.hei=%d,stSrcRect.wstride=%d,stSrcRect.hstride=%d\n",stSrcRect.wid, stSrcRect.hei, stSrcRect.wstride, stSrcRect.hstride);
    //printf("stSrcCodt.x=%d, stSrcCodt.y=%d,stSrcCodt.width=%d,stSrcCodt.height=%d\n",stSrcCodt.x, stSrcCodt.y, stSrcCodt.width, stSrcCodt.height);
    
    int iSrcWid = stSrcRect.wid;
    int iSrcHei = stSrcRect.hei;
    int iSrcWstride = stSrcRect.wstride;
    int iSrcHstride = stSrcRect.hstride;

    int iDstWid = stDstRect.wid;
    int iDstHei = stDstRect.hei;
    int iDstWstride = stDstRect.wstride;
    int iDstHstride = stDstRect.hstride;

    int iPatWid = stPatRect.wid;
    int iPatHei = stPatRect.hei;
    int iPatWstride = stPatRect.wstride;
    int iPatHstride = stPatRect.hstride;

    rga_buffer_t stSrcRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stSrcMb), iSrcWid, iSrcHei, RK_FORMAT_YCbCr_420_SP, iSrcWstride, iSrcHstride);
    rga_buffer_t stDstRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stDstMb), iDstWid, iDstHei,  RK_FORMAT_YCbCr_420_SP, iDstWstride, iDstHstride);
    rga_buffer_t stPatRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stPatMb), iPatWid, iPatHei,  RK_FORMAT_YCbCr_420_SP, iPatWstride, iPatHstride); 


    if((iSrcWid == iDstWid) && (iSrcHei == iDstHei))
    {
        iStatus = imcopy(stSrcRgaBuffer, stDstRgaBuffer, 1); //分辨率相同情况improcess会引起rga报错，所以使用imcopy
        if (iStatus != IM_STATUS_SUCCESS)
        {
            LOG_PrintError("imcopy failed: %s\n", imStrError(iStatus));
            iRet = -1;
        }
    }
    else
    {
        iStatus = improcess(stSrcRgaBuffer, stDstRgaBuffer, stPatRgaBuffer, stSrcCodt, stDstCodt, stPatCodt, usage);
        if (iStatus != IM_STATUS_SUCCESS)
        {
            LOG_PrintError("improcess failed: %s\n", imStrError(iStatus));
            iRet = -1;
        }
    }

    return iRet;
}


int VI_ImageSetCover(VI_ctl_t *pstEncCtl,ENC_ImageRect_t stRect,MEDIA_BUFFER stMb)
{
    int iRet    = 0;
    int iSync   = 1;
    int iStatus = 1;

    if (pstEncCtl->isCover)
    {
        im_rect imRect = {0, 0, stRect.wid, stRect.hei};
        int color = 0x00000000; /* color */

        rga_buffer_t stCurRgaBuffer = wrapbuffer_fd(RK_MPI_MB_GetFD(stMb), stRect.wid, stRect.hei, RK_FORMAT_YCbCr_420_SP);

        iStatus = imfill(stCurRgaBuffer, imRect, color, iSync);
        if (iStatus != IM_STATUS_SUCCESS)
        {
            LOG_PrintError("imfill failed: %s\n", imStrError(iStatus));
            return -1;
        }
    }

    return iRet;
}

int VI_YuvShowOsd(VI_ctl_t *pEncCtl, MEDIA_BUFFER srcOsdMb, 
                            MEDIA_BUFFER dstOsdMb, MEDIA_BUFFER dstMb)
{
    int dstOsdW, dstOsdH;
    unsigned char *pOsdBuf;
    int osdX = 128, osdY = 128;
    double fx, fy;
    IM_STATUS status;

    int iCurWid = 1920;
    int iCurHei = 1080;

    osdX = 128;
    osdY = 128;

    osdX = VIDEO_ALIGN_DOWN(osdX, 4);
    osdY = VIDEO_ALIGN_DOWN(osdY, 4);

    pOsdBuf = pEncCtl->logoInfo.pBuffer;
    dstOsdW = pEncCtl->logoInfo.stride;
    dstOsdH = pEncCtl->logoInfo.height;

    RK_MPI_MB_BeginCPUAccess(dstMb, RK_FALSE);
    ENC_CombineYuv(pOsdBuf, dstOsdW, dstOsdH, 
            (unsigned char*)RK_MPI_MB_GetPtr(dstMb),
            iCurWid, iCurHei, osdX, osdY);
    RK_MPI_MB_EndCPUAccess(dstMb, RK_FALSE);

    return 0;
}

int VI_ImageSetOsdAndMenu(VI_ctl_t *pstViCtl,ENC_ImageRect_t stRect,MEDIA_BUFFER stCurMb)
{
    int iRet    = 0;
    int status = 0;

    /* osd */
    if (pstViCtl->logoInfo.pBuffer)
    {
        iRet = VI_YuvShowOsd(pstViCtl, NULL, NULL, stCurMb);
        if (iRet)
        {
            LOG_PrintError("ENC_YuvShowOsd failed:%d\n",iRet);
            return -1;
        }
    }

    

    return iRet;
}

int VI_SendImageToList(int iChn,ENC_ImageBufInfo_t* pstImageInfo)
{
    int iRet = 0;
    ENC_listImageBufInfo_t stImageListBuf;
    ENC_ImageRect_t stSrcRect;
    ENC_ImageRect_t stDstRect;

    StreamExt_ctl_t* pstStreamExtCtrl = &(videoCtl_g.stStreamExtCtrl[iChn]);

    if(0 == pstStreamExtCtrl->iEnable)
    {
        return -1;
    }

    /* get  buffer for empty list */
    iRet = Stream_ListGetEmptyNode(iChn,&stImageListBuf);
    if(iRet)
    {
        return -1;
    }

    stSrcRect.wid = pstImageInfo->stRect.wid;
    stSrcRect.hei = pstImageInfo->stRect.hei;
    stSrcRect.wstride = stSrcRect.wid;
    stSrcRect.hstride = stSrcRect.hei;

    stDstRect.wid = stImageListBuf.stImageBufInfo.stRect.wid;
    stDstRect.hei = stImageListBuf.stImageBufInfo.stRect.hei;
    stDstRect.wstride = stDstRect.wid;
    stDstRect.hstride = stDstRect.hei;

    MEDIA_BUFFER stSrcMb = (MEDIA_BUFFER)pstImageInfo->revered;
    MEDIA_BUFFER stDstMb = (MEDIA_BUFFER)stImageListBuf.stImageBufInfo.revered;

    /* resize */
    iRet = VI_ImageResizeRga(stSrcRect,stDstRect,stSrcMb,stDstMb, RK_FORMAT_YCbCr_420_SP, RK_FORMAT_YCbCr_420_SP);
    if(iRet < 0)
    {
        LOG_PrintError("ENC_ImageResizeRga failed: %d\n",iRet);
        return -1;
    }

    stImageListBuf.stImageBufInfo.pts = pstImageInfo->pts;

    /* put  buffer to full list */
    iRet = Stream_ListPutFullNode(iChn,&stImageListBuf);
    if(iRet)
    {
        return -1;
    }

    return iRet;
}

int VI_SendImageToAllList(ENC_ImageBufInfo_t* pstImageInfo)
{
    int iRet    = 0;
    int iChn =0;

    for(int i=1;i<2;i++)
    {
        if(0 == i)
        {
            iChn = VIDEO_STREAM_1080P_LIST_CHN;
        }
        else if(1 == i)
        {
            iChn = VIDEO_STREAM_720P_LIST_CHN;
        }

        /* mb 1080-buffer and mb 720-buffer (get --> resize --> put) */
        VI_SendImageToList(iChn,pstImageInfo);
    }

    return iRet;
}

/*******************************************************************************
  Function:     ENC_SetCrop
  Description:  设置视频裁剪
  Input:        - pThiz: 视频编码接口指针
                - pCropCfg：视频裁剪配置
  Output:       无
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
static int VI_SetCrop(struct VideoInput *pThiz, VideoInCropCfg* pCropCfg)
{
    int ret = 0, result;
    VI_ctl_t  *pViCtl = NULL;
    VIDEO_picSize_t    picSize;
    VIDEO_resolution_t resolution;

    if (!pThiz || !pCropCfg)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&pViCtl->viChnMutex);

    pViCtl->isCrop        = pCropCfg->enable;
    pViCtl->imRect.x      = VIDEO_ALIGN_DOWN(pCropCfg->rect.x, 2);
    pViCtl->imRect.y      = VIDEO_ALIGN_DOWN(pCropCfg->rect.y, 2);
    pViCtl->imRect.width  = VIDEO_ALIGN_DOWN(pCropCfg->rect.w, 4);
    pViCtl->imRect.height = VIDEO_ALIGN_DOWN(pCropCfg->rect.h, 4);

    memcpy(&(pViCtl->imOrgRect),&(pViCtl->imRect),sizeof(im_rect) );

    if(videoViStreamMain == pViCtl->emViStream)
    {
        resolution = videoCtl_g.resolution;
    }
    else if(videoViStreamExtra1 == pViCtl->emViStream)
    {
        resolution = VIDEO_RESOLUTION_H1080;
    }

    VIDEO_GetPicSize(videoCtl_g.standard,
                     resolution,
                     &picSize,
                     videoCtl_g.rotate);

    if(pViCtl->imRect.x < 0)
    {
        pViCtl->imRect.x = 0;
    }
    if(pViCtl->imRect.y < 0)
    {
        pViCtl->imRect.y = 0;
    }

    if (pViCtl->imRect.x + pViCtl->imRect.width > picSize.u32Width)
    {
        pViCtl->imRect.width = VIDEO_ALIGN_DOWN(picSize.u32Width - pViCtl->imRect.x, 4);
    }

    if (pViCtl->imRect.y + pViCtl->imRect.height > picSize.u32Height)
    {
        pViCtl->imRect.height = VIDEO_ALIGN_DOWN(picSize.u32Height - pViCtl->imRect.y, 4);
    }

    if ( (pViCtl->imRect.width == picSize.u32Width) 
        && (pViCtl->imRect.height == picSize.u32Height) )
    {
        pViCtl->isCrop = 0;
    }

mutex_unlock:
    pthread_mutex_unlock(&pViCtl->viChnMutex);

    return ret;
}

static int VI_GetCrop(struct VideoInput *pThiz, VideoInCropCfg* pCropCfg)
{
    int ret = 0, result;
    VI_ctl_t  *pViCtl = NULL;
    VIDEO_picSize_t picSize, maxSize;

    if (!pThiz || !pCropCfg)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&pViCtl->viChnMutex);

    pCropCfg->enable = pViCtl->isCrop;

    if (pCropCfg->enable)
    {
        pCropCfg->rect.x = pViCtl->imOrgRect.x;
        pCropCfg->rect.y = pViCtl->imOrgRect.y;
        pCropCfg->rect.w = pViCtl->imOrgRect.width;
        pCropCfg->rect.h = pViCtl->imOrgRect.height;
    }
    else
    {
        VIDEO_GetPicSize(videoCtl_g.standard, 
                         videoCtl_g.resolution, 
                         &picSize,
                         videoCtl_g.rotate);

        VIDEO_GetPicSize(videoCtl_g.standard, 
                         videoCtl_g.resolution, 
                         &maxSize,
                         videoCtl_g.rotate);

        if ((maxSize.u32Width > picSize.u32Width)
            || (maxSize.u32Height > picSize.u32Height))
        {
            LOG_PrintError("width(%d), height(%d) is invalid.\n", picSize.u32Width, picSize.u32Height);
            ret = -1;
            goto mutex_unlock;
        }

        pCropCfg->rect.x = (picSize.u32Width  - maxSize.u32Width)/2;
        pCropCfg->rect.y = (picSize.u32Height - maxSize.u32Height)/2;
        pCropCfg->rect.w = maxSize.u32Width;
        pCropCfg->rect.h = maxSize.u32Height;
    }

mutex_unlock:
    pthread_mutex_unlock(&pViCtl->viChnMutex);

    return ret;
}

int VI_GetCropBlk(ENC_cropBlk_t *pCropBlk)
{
    int row = 15, column = 15;
    int uintRow, uintColumn;
    int xBlk, yBlk, wBlk, hBlk;
    VI_ctl_t *pViCtl = NULL;
    VIDEO_picSize_t picSize;

    pViCtl = videoCtl_g.pViCtl[0]; /* zoom-sensor */
    if (!pViCtl)
    {
        LOG_PrintError("pViCtl is NULL\n");
        return -1;
    }

    pthread_mutex_lock(&pViCtl->viChnMutex);

    VIDEO_GetPicSize(videoCtl_g.standard, 
                     videoCtl_g.resolution, 
                     &picSize,
                     videoCtl_g.rotate);

    if (pViCtl->isCrop)
    {
        uintRow    = picSize.u32Width/row;
        uintColumn = picSize.u32Height/column;

        int iXTmp  =  pViCtl->imRect.x;
        int iXBlk  =  iXTmp/uintRow    + (((iXTmp%uintRow) > ( uintRow*1/3) )?1:0);

        int iX2Tmp  = pViCtl->imRect.x + pViCtl->imRect.width;
        int iX2Blk   = iX2Tmp/uintRow    + (((iX2Tmp%uintRow) > ( uintRow*2/3) )?1:0);

        int iYTmp  =  pViCtl->imRect.y;
        int iYBlk  =  iYTmp/uintColumn  + (((iYTmp%uintColumn) > ( uintColumn*1/3) )?1:0);

        int iY2Tmp  = pViCtl->imRect.y  + pViCtl->imRect.height;
        int iY2Blk  = iY2Tmp/uintColumn + (((iY2Tmp%uintColumn) > ( uintColumn*2/3) )?1:0);

        pCropBlk->xBlk = iXBlk;
        pCropBlk->wBlk = iX2Blk;
        pCropBlk->yBlk = iYBlk;
        pCropBlk->hBlk = iY2Blk;


        /*//调整到中间区域
        if(pCropBlk->xBlk < ZOON_FOCUS_MIN)
        {
            pCropBlk->xBlk = ZOON_FOCUS_MIN;            
        }
        if(pCropBlk->yBlk < ZOON_FOCUS_MIN)
        {
            pCropBlk->yBlk = ZOON_FOCUS_MIN;
        }
        if(pCropBlk->wBlk > ZOON_FOCUS_MAX)
        {
            pCropBlk->wBlk = ZOON_FOCUS_MAX;
        }
        if(pCropBlk->hBlk > ZOON_FOCUS_MAX)
        {
            pCropBlk->hBlk = ZOON_FOCUS_MAX;
        }*/
#if 0
        printf("VI_GetCropBlk:xBlk=%d, yBlk=%d, wBlk=%d, hBlk=%d \n",
                    pCropBlk->xBlk, pCropBlk->yBlk, pCropBlk->wBlk, pCropBlk->hBlk);
#endif
    }
    else
    {
        pCropBlk->xBlk = 0;
        pCropBlk->wBlk = row;
        pCropBlk->yBlk = 0;
        pCropBlk->hBlk = column;
    }

    pthread_mutex_unlock(&pViCtl->viChnMutex);
    
    return 0;
}

int isNeedSendBuffer(int iViPipe)
{
    int iRet = 0;
    int iIsShow = 0;

    /* lock */
    if(0 == iViPipe)
    {
        iIsShow = 1;
    }
    else
    {
        iIsShow = 0;
    }
    /* unlock */

    return iIsShow;
}

int vdo_writeToFile(char* filePath,int size,void * pVir)
{
    int iRet = 0;

    FILE *fileHdl = NULL;
    /*open file*/

    if(NULL == filePath)
    {
        LOG_PrintError("vdo_writeToFile filePath is nullptr \n");
        return -1;
    }

    fileHdl= fopen(filePath, "wb");
    if (NULL == fileHdl)
    {
        LOG_PrintError("vdo_writeToFile: saveStream:[ER] wt file[%s] open error\n",filePath);
        return -1;
    }

    LOG_PrintInfo("vdo_writeToFile addr:%p size:%d \n",pVir, size);

    size_t count = 1;
    iRet = fwrite(pVir, size, count, fileHdl);
    if(iRet != count)
    {
        LOG_PrintError("vdo_writeToFile: filePath:%s fwrite failed iRet:%d  \n",filePath, iRet);
    }

    fflush(fileHdl);

    /*close file*/
    fclose(fileHdl);
    fileHdl = NULL;

    return 0;
}


int VI_Get1080PBufferForListEmpty(int iChn,ENC_listImageBufInfo_t* pstImageBuffer)
{
    int iRet = 0;

    StreamExt_ctl_t* pstStreamExtCtrl = &(videoCtl_g.stStreamExtCtrl[iChn]);

    if(0 == pstStreamExtCtrl->iEnable)
    {
        return -1;
    }

    /* get  buffer for empty list */
    iRet = Stream_ListGetEmptyNode(iChn,pstImageBuffer);
    if(iRet)
    {
        return -1;
    }

    return iRet;
}

int VI_Put1080PBufferToFullList(int iChn,ENC_listImageBufInfo_t* pstImageBuffer)
{
    int iRet = 0;

    StreamExt_ctl_t* pstStreamExtCtrl = &(videoCtl_g.stStreamExtCtrl[iChn]);

    iRet = Stream_ListPutFullNode(iChn,pstImageBuffer);
    if(iRet)
    {
        return -1;
    }

    return iRet;
}

int VI_IsCover()
{
    int iIsCover = 0;
    VI_ctl_t *pViCtl = NULL;

    for(int i=0; i<2;i++ )
    {
        int iChn = 0;

        if(0 == i)
        {
            iChn  = 0;
        }
        else if(1 == i)
        {
            iChn  = 1;
        }

        pViCtl = videoCtl_g.pViCtl[iChn];
        if(NULL != pViCtl)
        {
            if(pViCtl->isCover)
            {
                iIsCover = 1;
            }
        }

    }

    return iIsCover;
}

int VI_RadianCalculation(int x,int r)
{
    int y =0;
    int iTmp = 0;

    iTmp =  r*r - (x-r)*(x-r);

    y = sqrt(iTmp);

    return y;
}

int VI_yuv420PartCopy(Uint8* srcVir,Uint32 srcWid,Uint32 srcHei,
                                    Uint8* dstVir,Uint32 dstWid,Uint32 dstHei,
                                    Uint32 startX,Uint32 startY
                                    )
{
    int  iRet = 0;
    int i, j;
    int r = 28;
    int offset = 0;
    unsigned char *pSrcData    = srcVir;
    unsigned char *pDstData    = dstVir;

    unsigned char *pSrcDataNV = pSrcData + srcWid * srcHei;
    unsigned char *pDstDataNV = pDstData + dstWid * dstHei;
    //copy y
    for (i = 0; i < srcHei; i++)
    {
    #if 0
        if(i < r)
        {
            int offsetTmp = VI_RadianCalculation(i,r);
            offset = r - offsetTmp;
        }
        else if(i  > (srcHei - r) )
        {
            int iTmpI = srcHei - i;
            int offsetTmp = VI_RadianCalculation(iTmpI,r);
            offset = r - offsetTmp;
        }
        else
    #endif
        {
            offset = 0;
        }

        int iValidWid = srcWid - offset * 2;
    
        unsigned char *pSrcDataYTmp = pSrcData + srcWid * i + offset;
        unsigned char *pDstDataYTmp = pDstData + dstWid * (startY + i) + startX + offset;
        memcpy(pDstDataYTmp, pSrcDataYTmp, iValidWid);
    }

    for (i = 0; i < srcHei/2; i++)
    {
    #if 0
        if(i < r/2)
        {
            /* 4y--> u */
            int offsetTmp = VI_RadianCalculation(i,r/2);
            offset = r/2 - offsetTmp;
        }
        else if(i  > ((srcHei - r) /2 ) )
        {
            int iTmpI = srcHei/2 - i;
            int offsetTmp = VI_RadianCalculation(iTmpI,r/2);
            offset = r/2 - offsetTmp;
        }
        else
    #endif
        {
            offset = 0;
        }

        int iValidWid = srcWid - offset * 4; /* vu */

        unsigned char *pSrcDataNVTmp = pSrcDataNV + srcWid * i + offset*2;
        unsigned char *pDstDataNVTmp = pDstDataNV + dstWid * (startY  / 2 + i) + startX + offset*2;
        memcpy(pDstDataNVTmp, pSrcDataNVTmp, iValidWid);
    }

    return iRet;
}

int VI_SetPicInPicStatus(struct VideoInput *pThiz, int iPipStatus)
{
    int iRet = 0;

    LOG_PrintInfo("VI_SetPicInPicStatus:  pip status:%d \n",iPipStatus);

    videoCtl_g.iPipStatus = iPipStatus;

    return iRet;
}

#define  AI_PANORAMA_SHOT_MODE (5)

int VI_SetAiMode(struct VideoInput *pThiz, int iAiMode)
{
    int iRet = 0;

    LOG_PrintInfo("VI_SetPicInPicStatus:  iAiMode :%d \n",iAiMode);

    videoCtl_g.iAiMode = iAiMode;

    return iRet;
}

int VI_SetRoiCfg(struct VideoInput *thiz, VideoInRoiCfg* pstRoiCfg)
{
    int iRet = 0;
    VI_ctl_t *pViCtl = NULL;

    if( (NULL == pstRoiCfg) || (NULL == thiz) )
    {
        return -1;
    }

    pViCtl = (VI_ctl_t *)thiz->priv;

    pthread_mutex_lock(&pViCtl->viSecChnMutex);

    LOG_PrintInfo("VI_SetRoiCfg: enable:%d iRoiNum :%d \n",pstRoiCfg->enable,pstRoiCfg->iRoiNum);
    videoCtl_g.stRoiCfg.enable  = pstRoiCfg->enable;
    videoCtl_g.stRoiCfg.iRoiNum = pstRoiCfg->iRoiNum;

    for(int i=0;i<pstRoiCfg->iRoiNum;i++)
    {
        videoCtl_g.stRoiCfg.rect[i].x = pstRoiCfg->rect[i].x * VIDEO_STREAM_FIXED_SENSOR_PIP_WID / 1920;
        videoCtl_g.stRoiCfg.rect[i].y = pstRoiCfg->rect[i].y * VIDEO_STREAM_FIXED_SENSOR_PIP_HEI / 1080;
        videoCtl_g.stRoiCfg.rect[i].w = pstRoiCfg->rect[i].w * VIDEO_STREAM_FIXED_SENSOR_PIP_WID / 1920;
        videoCtl_g.stRoiCfg.rect[i].h = pstRoiCfg->rect[i].h * VIDEO_STREAM_FIXED_SENSOR_PIP_HEI / 1080;
        /* alinged */
        int iStartX = VIDEO_ALIGN_DOWN(VIDEO_STREAM_FIXED_SENSOR_PIP_WID,16);
        int iStartY = VIDEO_ALIGN_DOWN(VIDEO_STREAM_FIXED_SENSOR_PIP_HEI,16);

        /* mirror or flip */
        if(1 == pstRoiCfg->iMirror)
        {
            videoCtl_g.stRoiCfg.rect[i].x = VIDEO_STREAM_FIXED_SENSOR_PIP_WID - videoCtl_g.stRoiCfg.rect[i].x - videoCtl_g.stRoiCfg.rect[i].w;
        }
        if(1 == pstRoiCfg->iFlip)
        {
            videoCtl_g.stRoiCfg.rect[i].y = VIDEO_STREAM_FIXED_SENSOR_PIP_HEI - videoCtl_g.stRoiCfg.rect[i].y - videoCtl_g.stRoiCfg.rect[i].h;
        }

        videoCtl_g.stRoiCfg.rect[i].x = VIDEO_ALIGN_DOWN(videoCtl_g.stRoiCfg.rect[i].x + iStartX,16);
        videoCtl_g.stRoiCfg.rect[i].y = VIDEO_ALIGN_DOWN(videoCtl_g.stRoiCfg.rect[i].y + iStartY,16);
        videoCtl_g.stRoiCfg.rect[i].x = videoCtl_g.stRoiCfg.rect[i].x - iStartX;
        videoCtl_g.stRoiCfg.rect[i].y = videoCtl_g.stRoiCfg.rect[i].y - iStartY;
        if(videoCtl_g.stRoiCfg.rect[i].x < 0)
        {
            videoCtl_g.stRoiCfg.rect[i].x = 0;
        }
        if(videoCtl_g.stRoiCfg.rect[i].y < 0)
        {
            videoCtl_g.stRoiCfg.rect[i].y = 0;
        }
        videoCtl_g.stRoiCfg.rect[i].w = VIDEO_ALIGN_DOWN(videoCtl_g.stRoiCfg.rect[i].w,16);
        videoCtl_g.stRoiCfg.rect[i].h = VIDEO_ALIGN_DOWN(videoCtl_g.stRoiCfg.rect[i].h,16);
        LOG_PrintInfo("VI_SetRoiCfg: index:%d 1080p-(x,y):(%d,%d) (w*h):(%d*%d) --> pip-(x,y):(%d,%d) (w*h):(%d*%d)\n",i,
                                       pstRoiCfg->rect[i].x,
                                       pstRoiCfg->rect[i].y,
                                       pstRoiCfg->rect[i].w,
                                       pstRoiCfg->rect[i].h,
                                       videoCtl_g.stRoiCfg.rect[i].x,
                                       videoCtl_g.stRoiCfg.rect[i].y,
                                       videoCtl_g.stRoiCfg.rect[i].w,
                                       videoCtl_g.stRoiCfg.rect[i].h);
    }

    pthread_mutex_unlock(&pViCtl->viSecChnMutex);

    return iRet;
}


int VI_GetPicInPicStatus()
{
    int iPipStatus = 0;

    if(AI_PANORAMA_SHOT_MODE != videoCtl_g.iAiMode)
    {
        if(1 == videoCtl_g.iPipStatus)
        {
            iPipStatus = 1;
        }
    }

    if(0 == iPipStatus)
    {
        Stream_CleanBufferList(VIDEO_STREAM_FIXED_SENSOR_PIP_LIST_CHN);
    }

    return iPipStatus;
}

int VI_ImageMosaic(ENC_listImageBufInfo_t* pstImageBuffer)
{
    int iRet = 0;
    int iChn = VIDEO_STREAM_FIXED_SENSOR_PIP_LIST_CHN;
    /* mosaic */

    ENC_listImageBufInfo_t stMiniImageBuffe;
    memset(&stMiniImageBuffe,0x0,sizeof(ENC_listImageBufInfo_t));
    int iPipStatus  = VI_GetPicInPicStatus();

    if( 0 == iPipStatus )
    {
        return 0;
    }

    /* get src-buffer */
    iRet = Stream_ListGetFullNode(iChn,&stMiniImageBuffe);
    if(iRet)
    {
        return -1;
    }
    long long ts_start = vdo_get_time();

    MEDIA_BUFFER stMbTmp = (MEDIA_BUFFER)pstImageBuffer->stImageBufInfo.revered;

    /* PIP */
    Uint8* srcVir = (Uint8*)stMiniImageBuffe.stImageBufInfo.pBuf;
    Uint32 srcWid = stMiniImageBuffe.stImageBufInfo.stRect.wid;
    Uint32 srcHei = stMiniImageBuffe.stImageBufInfo.stRect.hei;
    Uint8* dstVir = (Uint8*)pstImageBuffer->stImageBufInfo.pBuf;
    Uint32 dstWid = pstImageBuffer->stImageBufInfo.stRect.wid;
    Uint32 dstHei = pstImageBuffer->stImageBufInfo.stRect.hei;
    Uint32 startX = (dstWid - srcWid) / 2;
    Uint32 startY = dstHei - srcHei;

    RK_MPI_MB_BeginCPUAccess(stMbTmp, RK_FALSE);

    VI_yuv420PartCopy(srcVir,srcWid,srcHei,dstVir,dstWid,dstHei,startX,startY);

    RK_MPI_MB_EndCPUAccess(stMbTmp, RK_FALSE);

    long long ts_stop = vdo_get_time();

    //printf("VI_ImageMosaic use time :%lld \n",(ts_stop - ts_start));
    /* put dst-buffer */
    iRet = Stream_ListPutEmptyNode(iChn,&stMiniImageBuffe);
    if(iRet)
    {
        return -1;
    }

    return iRet;
}


/*******************************************************************************
  Function:     ENC_UserBindVpss
  Description:  venc通道绑定vpss通道线程
  Input:        - parg:                  
  Output:       无
  Return:       NULL
  Others:       无
*******************************************************************************/
static void *VI_MediaThd(void *parg)
{
    MEDIA_BUFFER stSrcMb  = NULL;
    MEDIA_BUFFER stCropMb = NULL;
    MEDIA_BUFFER stCurMb = NULL;

    int iCurWid = 0;
    int iCurHei = 0;
    int iResizeWid_1080p = 1920;
    int iResizeHei_1080p = 1080;

    ENC_ImagePonit_t stDstPoint = {0,0};
    ENC_ImageRect_t  stSrcRect  = {0,0};
    ENC_ImageRect_t  stDstRect  = {0,0};

    ENC_listImageBufInfo_t stImageBuffer;

    VI_ctl_t *pstViCtl = (VI_ctl_t *)parg;
    IM_STATUS status;

    int ret = 0;
    VIDEO_picSize_t picSize = {0};
    int mbSize;
    int size;
    int sync = 1;

    float srcFps = 30.0;
    float dstFps = 30.0;
    float fpsRatio = 0.0;
    float calcVal  = 0.0;
    float residual = 0.0;
    int   frameCnt = 0;
    int   isSavePic = 0;

    int iViPipe = pstViCtl->iViPipe;
    int iChn    = pstViCtl->iViChn;

    long long ts_start = vdo_get_time();
    long long ts_now;
    int iFrameCount = 0;
    int iShowFps = 1;

    LOG_PrintInfo("tid:%d vi-pipe:%d-chn:%d \n", gettid(),iViPipe,iChn);

    VIDEO_GetPicSize(videoCtl_g.standard, 
                         videoCtl_g.resolution, 
                         &picSize,
                         videoCtl_g.rotate);

    mbSize = picSize.u32Width * picSize.u32Height * 3 / 2;
    stCropMb = RK_MPI_MB_CreateBuffer(mbSize, RK_TRUE, 0);
    if (!stCropMb)
    {
        LOG_PrintError("Fail to RK_MPI_MB_CreateBuffer!\n");
        return NULL;
    }


    while (1)
    {
        stSrcMb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, iChn, -1/*10ms */);
        if (!stSrcMb) 
        {
            LOG_PrintError("Fail to RK_MPI_SYS_GetMediaBuffer for chn-%d! \n",iChn);
            continue;
        }

        pthread_mutex_lock(&pstViCtl->viChnMutex);

#if 0
        /* vi-stream ctrl */
        int isSendStatus = isNeedSendBuffer(iViPipe);
        if(0 == isSendStatus)
        {
            usleep(10*1000/* 1ms */);
            goto release_buffer;
        }
#else
        if(0 == pstViCtl->iEnable)
        {
            usleep(10*1000/* 1ms */);
            goto release_buffer;
        }
#endif
        dstFps = 30;//videoCtl_g.fps;//pEncCtl->fps;
        srcFps = videoCtl_g.fps;
        fpsRatio = dstFps/srcFps;

        frameCnt++;
        calcVal = fpsRatio*frameCnt + residual;
        if (calcVal < 1.0)
        {
            goto release_buffer;
        }
        else
        {
            residual = calcVal - 1.0;
            frameCnt = 0;
        }

        /* step1:get vi buffer-info and do eptz */
        MB_IMAGE_INFO_S stSrcMbInfo;
        if (NULL == stSrcMb)
        {
            goto release_buffer;
        }

        RK_MPI_MB_GetImageInfo(stSrcMb, &stSrcMbInfo);
        stCurMb = stSrcMb;
        iCurWid = stSrcMbInfo.u32Width;
        iCurHei = stSrcMbInfo.u32Height;

        /* more 4k noting to do(rga not enough)  */
        if (0) //(pEncCtl->encPicSize.u32Width >= 3840) || (pEncCtl->encPicSize.u32Height >= 2160))
        {
            /* no thing to do */
        }
        else
        {
            /* step1.2: set crop */
            if (pstViCtl->isCrop)
            {
                memset(&stDstPoint,0x0,sizeof(ENC_ImagePonit_t));
                memset(&stSrcRect ,0x0,sizeof(ENC_ImageRect_t));
                memset(&stDstRect ,0x0,sizeof(ENC_ImageRect_t));


                stSrcRect.wid = stSrcMbInfo.u32Width;
                stSrcRect.hei = stSrcMbInfo.u32Height;

                stDstPoint.x  = pstViCtl->imRect.x;
                stDstPoint.y  = pstViCtl->imRect.y;
                stDstRect.wid = pstViCtl->imRect.width;
                stDstRect.hei = pstViCtl->imRect.height;
                ret = VI_ImageCropRga(stSrcRect,stDstPoint,stDstRect,stCurMb,stCropMb);
                if(ret)
                {
                    LOG_PrintError("ENC_ImageCropRga failed: %d\n", ret);
                    goto release_buffer;
                }

                stCurMb = stCropMb;
                iCurWid = stDstRect.wid;
                iCurHei = stDstRect.hei;

            }

            /* step1.3: resize */
            /* step1.3.1 get 1080_list buffers */
            ret = VI_Get1080PBufferForListEmpty(VIDEO_STREAM_1080P_LIST_CHN,&stImageBuffer);
            if(ret)
            {
                goto release_buffer;
            }

            MEDIA_BUFFER st1080MbTmp = (MEDIA_BUFFER)stImageBuffer.stImageBufInfo.revered;

            memset(&stSrcRect ,0x0,sizeof(ENC_ImageRect_t));
            memset(&stDstRect ,0x0,sizeof(ENC_ImageRect_t));

            stSrcRect.wid = iCurWid;
            stSrcRect.hei = iCurHei;
            stSrcRect.wstride = stSrcRect.wid;
            stSrcRect.hstride = stSrcRect.hei;

            stDstRect.wid = stImageBuffer.stImageBufInfo.stRect.wid;
            stDstRect.hei = stImageBuffer.stImageBufInfo.stRect.hei;
            stDstRect.wstride = stDstRect.wid;
            stDstRect.hstride = stDstRect.hei;

            stImageBuffer.stImageBufInfo.pts = RK_MPI_MB_GetTimestamp(stSrcMb); /* pts */

            ret = VI_ImageResizeRga(stSrcRect,stDstRect,stCurMb,st1080MbTmp, RK_FORMAT_YCbCr_420_SP, RK_FORMAT_YCbCr_420_SP);
            if(ret)
            {
                LOG_PrintError("ENC_ImageResizeRga failed: %d\n",ret);
                goto release_buffer;
            }

            stCurMb = st1080MbTmp;
            iCurWid = stDstRect.wid;
            iCurHei = stDstRect.hei;

        }

        /* PIP */
        VI_ImageMosaic(&stImageBuffer);

        /* step2: cover and osd */
        /* step2.1:  cover */
        memset(&stSrcRect ,0x0,sizeof(ENC_ImageRect_t));
        stSrcRect.wid = iCurWid;
        stSrcRect.hei = iCurHei;
        ret = VI_ImageSetCover(pstViCtl,stSrcRect,stCurMb);
        if(ret)
        {
            LOG_PrintError("ENC_ImageResizeRga failed: %d\n",ret);
            goto release_buffer;
        }

        /* step2.2: osd menu */
        ret =  VI_ImageSetOsdAndMenu(pstViCtl,stSrcRect,stCurMb);
        if(ret)
        {
            LOG_PrintError("ENC_ImageResizeRga failed: %d\n",ret);
            goto release_buffer;
        }

        if (!sync)
        {
            imsync();
        }

        /* step3.set pts */
        RK_MPI_MB_SetTimestamp(stCurMb, RK_MPI_MB_GetTimestamp(stSrcMb));


        /* step4: send  buffer to buffer_list */
        ENC_ImageBufInfo_t stImageInfo;

        stImageInfo.revered    = stCurMb;
        stImageInfo.stRect.wid = iCurWid;
        stImageInfo.stRect.hei = iCurHei;
        stImageInfo.pts = RK_MPI_MB_GetTimestamp(stSrcMb); /* pts */

        VI_SendImageToAllList(&stImageInfo);

        /* put 1080p list buffer */
        VI_Put1080PBufferToFullList(VIDEO_STREAM_1080P_LIST_CHN,&stImageBuffer);

        if(1 == isSavePic)
        {
            char path[64];
            sprintf(path,"/tmp/zhengyc/image_chn%d.yuv",iChn);
            int size = stImageInfo.stRect.wid * stImageInfo.stRect.hei *3/2;
            void* pVir = RK_MPI_MB_GetPtr(stCurMb);
            vdo_writeToFile(path,size,pVir);

            isSavePic = 0;
        }

        if(1 == iShowFps)
        {
            int iPeriod = 30; /* ms */
            iFrameCount++;
            ts_now = vdo_get_time();
            if(ts_now - ts_start > iPeriod*1000)
            {
                LOG_PrintInfo("vi-pipe%d-chn%d, %0.2f fps in %ds,count %d  src-w*h:(%d*%d) --> crop-w*h:(%d*%d)  --> dst-w*h:(%d*%d)\n",iViPipe,iChn,(float)1.0*iFrameCount/iPeriod,
                    iPeriod,
                    iFrameCount,
                    stSrcMbInfo.u32Width,
                    stSrcMbInfo.u32Height,
                    pstViCtl->imRect.width,
                    pstViCtl->imRect.height,
                    iCurWid,
                    iCurHei
                    );

                ts_start = ts_now;
                iFrameCount = 0;
            }
        }
release_buffer:
        if (stSrcMb)
        {
            RK_MPI_MB_ReleaseBuffer(stSrcMb);
            stSrcMb = NULL;
        }

        pthread_mutex_unlock(&pstViCtl->viChnMutex);
    }

    return NULL;
}




int VI_GetCfg(VI_ctl_t *pstViCtl)
{
    int iRet = 0;
    VIDEO_picSize_t picSize;
    RK_CHAR *pDeviceName = NULL;

    memset(&picSize,0x0,sizeof(VIDEO_picSize_t));

    switch(pstViCtl->emViStream)
    {
        case videoViStreamMain:
        {
            VIDEO_GetPicSize(videoCtl_g.standard, 
                             videoCtl_g.resolution, 
                             &picSize,
                             videoCtl_g.rotate);

            pstViCtl->iViPipe = 0;
            pstViCtl->iViChn  = 0;
            pDeviceName      = "rkispp_m_bypass";

            break;
        }
        case videoViStreamExtra1:
        {
            VIDEO_GetPicSize(videoCtl_g.standard, 
                             VIDEO_RESOLUTION_H1080, 
                             &picSize,
                             videoCtl_g.rotate);

            pstViCtl->iViPipe = 1;
            pstViCtl->iViChn  = 2;
            pDeviceName      = "rkispp_m_bypass";

            break;
        }
        default:
        {
            break;
        }
    }

    VI_CHN_ATTR_S * pViChnAttr = &(pstViCtl->stViChnAttr);

    pViChnAttr->pcVideoNode = pDeviceName;
    pViChnAttr->u32BufCnt   = 3;
    pViChnAttr->u32Width    = picSize.u32Width;
    pViChnAttr->u32Height   = picSize.u32Height;
    pViChnAttr->enPixFmt    = IMAGE_TYPE_NV12;
    pViChnAttr->enWorkMode  = VI_WORK_MODE_NORMAL;
    pViChnAttr->enBufType   = VI_CHN_BUF_TYPE_DMA;

    return 0;
}

int VI_EnableViMod(VI_ctl_t *pstViCtl)
{
    int iRet = 0;

    if(NULL == pstViCtl)
    {
        return -1;
    }

    iRet = VI_GetCfg(pstViCtl);
    if (iRet)
    {
        LOG_PrintError("Fail to get encode config!\n");
        return  -1;
    }

    iRet = VI_RkEnableChn(pstViCtl->iViPipe, pstViCtl->iViChn, &pstViCtl->stViChnAttr);
    if (iRet)
    {
        LOG_PrintError("Fail to create encode channel!\n");
        return  -1;
    }

    iRet = RK_MPI_VI_StartStream(pstViCtl->iViPipe, pstViCtl->iViChn);
    if (iRet)
    {
        LOG_PrintError("Fail to RK_MPI_VI_StartStream chn(%d) with ret=%d\n",
                        pstViCtl->viChn, iRet);
        return  -1;
    }

    return iRet;
}

int VI_EnableViStream(struct VideoInput *pThiz, int enables)
{
    int iRet = 0;

    VI_ctl_t  *pViCtl = NULL;

    if (!pThiz)
    {
        LOG_PrintError("Input parameter is NULL\n");
        return -1;
    }

    pViCtl = (VI_ctl_t *)pThiz->priv;
    if (!pViCtl)
    {
        LOG_PrintError("VideoInput isn't initialized\n");
        return -1;
    }

    pthread_mutex_lock(&pViCtl->viChnMutex);

    if(pViCtl->iEnable != enables)
    {
        LOG_PrintInfo("vi-Chn:%d old-enable:%d --> new-enable:%d \n",pViCtl->iViChn,pViCtl->iEnable,enables);
    }

    pViCtl->iEnable  =  enables;

    pthread_mutex_unlock(&pViCtl->viChnMutex);

    return iRet;
}

/*******************************************************************************
    Function:     VI_GetFullFromList
    Description:  从full对列取数据
    Input:        - pThiz: 视频输入接口指针
    Output:       - pListPacket：获取队列的节点数据指针
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
  *******************************************************************************/
int VI_GetFullFromList(VI_ctl_t *pViCtl, COMM_ListInfo_t* pListPacket) 
{
    int ret = 0;
    if (!pViCtl)
    {
        LOG_PrintError("pViCtl is NULL\n");
        return -1;
    }
    
    //LOG_PrintError("VI_GetFullFromList enter\n");
    
    COMM_ListInfo_t* pListFrame = NULL; 

    ///get node from list
    pthread_mutex_lock(&pViCtl->bufLock);
    if(!list_empty(&pViCtl->fullBuf))
    {
        pListFrame = list_first_entry(&pViCtl->fullBuf, COMM_ListInfo_t, list);
        list_del(&pListFrame->list);
        
        memcpy(pListPacket, pListFrame,sizeof(COMM_ListInfo_t)); //浅拷贝
        pListPacket->revered = pListFrame; //记录指针后续返还
        pthread_mutex_unlock(&pViCtl->bufLock);

        //LOG_PrintError("VI_GetFullFromList get list\n");
    }
    else
    {
        pthread_mutex_unlock(&pViCtl->bufLock);

        //LOG_PrintError("fullBuf is NULL\n");
        ret = -1;
    } 


    //LOG_PrintError("VI_GetFullFromList leave\n");

    return ret;
}

 /*******************************************************************************
    Function:     VI_PutEmptyToList
    Description:  将节点放回empty队列
    Input:        - pThiz: 视频输入接口指针
                  - pListPacket：放回队列的节点数据指针
    Output:       无
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
  *******************************************************************************/
int VI_PutEmptyToList(VI_ctl_t *pViCtl, COMM_ListInfo_t* pListPacket) 
{
    if (!pViCtl)
    {
        LOG_PrintError("pViCtl is NULL\n");
        return -1;
    }
    
    //pthread_mutex_lock(&videoCtl_g.viMutex);

    COMM_ListInfo_t* pListFrame = (COMM_ListInfo_t*)pListPacket->revered; 

    ///put node to list
    pthread_mutex_lock(&pViCtl->bufLock); 
    list_add_tail(&pListFrame->list, &pViCtl->emptyBuf);
    pthread_mutex_unlock(&pViCtl->bufLock);
    
    //pthread_mutex_unlock(&videoCtl_g.viMutex);

    return 0;
}

int HdmiInStatus()
{
    return connectStatus_s;
}

static int VI_DeinitList(VI_ctl_t *pViCtl)
{
    COMM_ListInfo_t *pListFrame;
    
    while (!list_empty(&pViCtl->fullBuf))
    {
        pListFrame = list_first_entry(&pViCtl->fullBuf, COMM_ListInfo_t, list);
        list_del(&pListFrame->list);
        list_add_tail(&pListFrame->list, &pViCtl->emptyBuf);
    }
            
    return 0;
}

int hdmiDbStatus(){
    if(lt6911cArgs_s.hdmiInState.width == 0 || lt6911cArgs_s.hdmiInState.height == 0){
        return -1;
    }else{
        return 0;
    }
}


static void *VI_MediaHdmiThd(void *parg)
{
    VI_ctl_t *pViCtl = (VI_ctl_t *)parg;
    if(!pViCtl)
    {
        LOG_PrintInfo("pViCtl is NULL\n");
        return NULL;     
    }

    STREAM_composeCtl_t* pComposeCtl = videoCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }
    
    int ret;
    int fdLt6911c;
    VI_CHN viChn;
    VI_PIPE viPipe;
    VI_CHN_ATTR_S viChnAttr;
    
    MEDIA_BUFFER srcMb = NULL;
    size_t decLen = 0;
    COMM_ListInfo_t *pListFrame;
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo;
    VideoMixerInfo videoMixerInfo = {0};
    StreamInfo stream = {0};
    ScreenCodt codt = {0}; 
    int outNum = 0;
    int pictureNum = 0;
    int dealNum = 0;
    ENC_ImageRect_t stSrcRect = {0};
    ENC_ImageRect_t stDstRect = {0};
    PlayState state = IDLE;
    PlayState lastState = IDLE;

    long long cnt_tmp = 0;
    unsigned long long ts = 0;
    static uint64_t lastPts_s = 0;

    float srcFps = 60.0;
    float dstFps = 30.0;
    float fpsRatio = dstFps/srcFps;
    float calcVal  = 0.0;
    float residual = 0.0;
    int   frameCnt = 0;
        
    fdLt6911c= open("/dev/"LT6911C_DEV_NAME, O_RDWR);
    if (fdLt6911c < 0)
    {
        LOG_PrintError("open %s dev failed!\n", LT6911C_DEV_NAME);
        return NULL;
    }

    memset(&viChnAttr, 0, sizeof(viChnAttr));
    viPipe = 0;
    viChn = videoCtl_g.viChnIndex++;
    viChnAttr.pcVideoNode = videoCtl_g.ispDeviceName[viChn]; // dev/video0
    viChnAttr.u32BufCnt = 4;
    viChnAttr.u32Width = HDMIIN_WIDTH;
    viChnAttr.u32Height = HDMIIN_HEIGHT;
    viChnAttr.enPixFmt = IMAGE_TYPE_UYVY422; //IMAGE_TYPE_NV12
    viChnAttr.enWorkMode = VI_WORK_MODE_NORMAL;
    viChnAttr.enBufType = VI_CHN_BUF_TYPE_DMA; //VI_CHN_BUF_TYPE_MMAP //VI_CHN_BUF_TYPE_DMA

    static long long hdmiCnt = 0;
 
    while (1)
    {  
        ret = ioctl(fdLt6911c, LT6911C_GET_HDMIIN, &lt6911cArgs_s);
        if (ret < 0)
        {
            LOG_PrintError("Fail to ioctl get lt9611 args.\n");
            continue;
        }

        if (connectStatus_s != lt6911cArgs_s.hdmiInState.connect)
        {
            LOG_PrintWarn("connectStatus_s=%d,lt6911cArgs_s.hdmiInState.connect=%d\n",connectStatus_s, lt6911cArgs_s.hdmiInState.connect);
            if (1 == connectStatus_s)
            {
                ret = VI_RkDisableChn(viPipe, viChn);
                if (ret)
                {
                    LOG_PrintError("Fail to create encode channel!\n");
                    continue;
                } 
            }
            else
            {
                viChnAttr.u32Width = lt6911cArgs_s.hdmiInState.width;
                viChnAttr.u32Height = lt6911cArgs_s.hdmiInState.height;
                ret = VI_RkEnableChn(viPipe, viChn, &viChnAttr);
                if (ret)
                {
                    LOG_PrintError("Fail to create encode channel!\n");
                    continue;
                }  

                ret = RK_MPI_VI_StartStream(viPipe, viChn);
                if (ret)
                {
                    LOG_PrintError("Fail to RK_MPI_VI_StartStream chn(%d) with ret=%d\n",
                                    viChn, ret);
                    continue;
                }
            }

            connectStatus_s = lt6911cArgs_s.hdmiInState.connect;
        }

        if (!connectStatus_s)
        {
            usleep(1000*30);
            continue;
        }
        
        srcMb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VI, viChn, 100);
        if (!srcMb) 
        {
            LOG_PrintError("Fail to RK_MPI_SYS_GetMediaBuffer!\n");
            continue;
        }

        decLen = RK_MPI_MB_GetSize(srcMb);
        if(decLen == 0)
        {
            LOG_PrintError("decLen is 0!\n");
            goto release_buffer;
        }


        ///帧率控制        
        frameCnt++;
        calcVal = fpsRatio*frameCnt + residual;
        if (calcVal < 1.0)
        {
            goto release_buffer;
        }
        else
        {
            residual = calcVal - 1.0;
            frameCnt = 0;
        }

        MB_IMAGE_INFO_S stImageInfo = {0};
        RK_MPI_MB_GetImageInfo(srcMb, &stImageInfo);

        if(hdmiCnt++ % 320 == 0)
        {
            LOG_PrintWarn("RK_MPI_SYS_GetMediaBuffer viChn:%d,ImgInfo:<wxh %dx%d, fmt 0x%x>, HorStride:%d, VerStride:%d, size:%u\n",
                 pViCtl->viChn, stImageInfo.u32Width,
                 stImageInfo.u32Height, stImageInfo.enImgType,
                 stImageInfo.u32HorStride,
                 stImageInfo.u32VerStride,
                 RK_MPI_MB_GetSize(srcMb));
        }
             
        //FILE_write("wyg/hdmiin.yuv", RK_MPI_MB_GetPtr(srcMb), RK_MPI_MB_GetSize(srcMb));

        getCurtainPlayState(&state);
        if(state != RUNNING)
        {
            //LOG_PrintWarn("state: %d\n", state);

            if(lastState == RUNNING)
            {
                lastState = state;
                VI_DeinitList(pViCtl);
            }
            goto release_buffer;
        }
        lastState = state;
             
        getCurtainLayout(&curtainInfo); //获取拼接布局
        outNum = curtainInfo.outNum;
        if(outNum <= 0)
        {            
            //LOG_PrintWarn("outNum is 0\n");
            goto release_buffer;
        }

        /*ts = vdo_get_time();*/
                     
        dealNum = 0;
        int displayChn = 0;
        for(int i = 0; i < outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];
            
            videoMixerInfo = configInfo.videoMixerInfo;

            for(int j = 0; j < videoMixerInfo.totalPictures; ++j)
            {
                stream = videoMixerInfo.videoInfo[j].videoStream;
                codt = videoMixerInfo.videoInfo[j].codt;

                if(stream.type == HDMIIN_STREAM)
                { 
                    ///getlist -- getbuffer -- buffer deal -- addlist
                    pthread_mutex_lock(&pViCtl->bufLock);
                    if(!list_empty(&pViCtl->emptyBuf))
                    {
                        pListFrame = list_first_entry(&pViCtl->emptyBuf, COMM_ListInfo_t, list);
                        list_del(&pListFrame->list);
                        pthread_mutex_unlock(&pViCtl->bufLock);

                        //LOG_PrintWarn("emptyBuf list is get!,viChn=%d\n",vdecChn);
                    }
                    else
                    {
                        pthread_mutex_unlock(&pViCtl->bufLock);
                        //LOG_PrintWarn("emptyBuf list is empty!\n");
                        goto release_buffer;
                    }

                    displayChn = stream.displayChn;
                    
                #if 1    
                    int srcW = stImageInfo.u32Width;
                    int srcH = stImageInfo.u32Height;
                    int pictureW = codt.width;
                    int pictureH = codt.height;
                    
                    stDstRect.wid = pictureW;
                    stDstRect.hei = pictureH;
                    stDstRect.wstride = stDstRect.wid;
                    stDstRect.hstride = stDstRect.hei;
                 
                    ///HDMI获取Buf需要resize后使用，不可直接送编码或存list，否则HDMI插拔后重新启动会失败
                    {
                        pListFrame->isNocopy = 0; 
                        
                        /* resize,大于1路时，若展示分辨率一致，后续可以复用,否则拼接处再resize*/
                        stSrcRect.wid = srcW;
                        stSrcRect.hei = srcH;
                        stSrcRect.wstride = stImageInfo.u32HorStride;
                        stSrcRect.hstride = stImageInfo.u32VerStride;

                        if(VI_ImageResizeRga(stSrcRect, stDstRect, srcMb, pListFrame->mdResizeBuf, RK_FORMAT_UYVY_422, RK_FORMAT_YCbCr_420_SP) < 0)
                        {
                            LOG_PrintError("VI_ImageResizeRga failed ..!\n"); 
                            break;
                        } 
                    }

                 #else

                    stDstRect.wid = stImageInfo.u32Width;
                    stDstRect.hei = stImageInfo.u32Height;
                    stDstRect.wstride = stDstRect.wid;
                    stDstRect.hstride = stDstRect.hei;

                    unsigned long long ts = vdo_get_time();

                    RK_MPI_MB_BeginCPUAccess(pListFrame->mdResizeBuf, RK_FALSE);
                    ConvertUYVY422ToYUV420SP(RK_MPI_MB_GetPtr(srcMb), RK_MPI_MB_GetPtr(pListFrame->mdResizeBuf), stImageInfo.u32Width, stImageInfo.u32Height);
                    RK_MPI_MB_EndCPUAccess(pListFrame->mdResizeBuf, RK_FALSE);

                    {
                        unsigned long long  runtime = vdo_get_time() - ts;
                        //printf("ConvertUYVY422ToYUV420SP runtime=%llu\n",runtime);
                    }
                    
                 #endif

                    pListFrame->stImageInfo = stDstRect;                                
                    pListFrame->streamType = stream.type;
                    pListFrame->pts = vdo_get_time();

                    if((pListFrame->pts <= lastPts_s) && (lastPts_s > 0))
                    {
                        pListFrame->pts = lastPts_s + 1;
                    }
                    lastPts_s = pListFrame->pts;

                    dealNum++;
                    break; //找到一路即返回
                }
            }
            
            if(dealNum > 0) //找到一路即返回
            break;
        }    

        if(dealNum > 0) //加入list
        {
             ///put node to full list
            pthread_mutex_lock(&pViCtl->bufLock);
            list_add_tail(&pListFrame->list, &pViCtl->fullBuf);
            pthread_mutex_unlock(&pViCtl->bufLock);

            pComposeCtl->newPts[displayChn] = pListFrame->pts; //更新buf时间
        
            /*if(cnt_tmp++ % 10 == 0)
            {
                unsigned long long  runtime = vdo_get_time() - ts;
                LOG_PrintWarn("Compose_DataComposeThd::dealPacket runtime=%llu\n",runtime);
            } */
        }
        else 
        {
            if(pListFrame)
            {
                ///put node to empty list
                pthread_mutex_lock(&pViCtl->bufLock); 
                list_add_tail(&pListFrame->list, &pViCtl->emptyBuf);
                pthread_mutex_unlock(&pViCtl->bufLock);
            }
        }

release_buffer:
        RK_MPI_MB_ReleaseBuffer(srcMb);
        pListFrame = NULL;
    }
    
    return NULL;
}


/*******************************************************************************
  Function:     createVideoInput
  Description:  创建视频输入接口
  Input:        - pViDesc: 视频输入接口描述结构VideoInDesc指针
  Output:       - ppVideoInput: 视频输入接口指针的指针
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int PAL_API createVideoInput(VideoInDesc *pViDesc, VideoInput **ppVideoInput)
{
    int ret = 0;
    VideoInput *pVideoInput;
    VI_ctl_t *pViCtl;

    if ((NULL == pViDesc) || (NULL == ppVideoInput))
    {
        LOG_PrintError("Parameter is NULL!\n");
        return -1;
    }

    if (pViDesc->channel >= videoCtl_g.viChnNum)
    {
        LOG_PrintError("Video input Channel (%d) is out of range!\n", 
                       pViDesc->channel);
        return -1;
    }

    pthread_mutex_lock(&videoCtl_g.viMutex);

    pViCtl = videoCtl_g.pViCtl[pViDesc->channel];
    if (pViCtl)
    {
        LOG_PrintInfo("video input has already been created\n");
        pViCtl->refCount++;
        *ppVideoInput = &pViCtl->videoInput;
        goto mutex_unlock;
    }

    pViCtl = (VI_ctl_t *)malloc(sizeof(VI_ctl_t));
    if (!pViCtl)
    {
        LOG_PrintError("There is no enough memory to allocate VideoEncoder!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pViCtl, 0, sizeof(VI_ctl_t));

    pViCtl->refCount++;
    pViCtl->viChn = pViDesc->channel;

    videoCtl_g.pViCtl[pViDesc->channel] = pViCtl;

#if 1
    cJSON *pJson =  NULL;    
    pJson = CFG_GetItem(NULL, "hdmiIn");
    if (!pJson)
    {
        LOG_PrintError("Fail to get config hdmiIn!\n");
        return -1; 
    }

#endif

#if 1
    pViCtl->maxBufLen = HDMIIN_WIDTH * HDMIIN_HEIGHT *3/2; //倍数待定，todo
    INIT_LIST_HEAD(&pViCtl->emptyBuf);
    INIT_LIST_HEAD(&pViCtl->fullBuf);
    pthread_mutex_init(&pViCtl->bufLock, NULL);
    for (int i = 0; i < 5; i++)
    {
        pViCtl->listBuf[i].mdResizeBuf = RK_MPI_MB_CreateBuffer(pViCtl->maxBufLen, RK_TRUE, 0);
        if (!pViCtl->listBuf[i].mdResizeBuf)
        {
            LOG_PrintError("Fail to malloc!\n");
            ret = -1;
            goto free_ctl;
        }
	    list_add_tail(&pViCtl->listBuf[i].list, &pViCtl->emptyBuf);
	}

    ret = pthread_create(&pViCtl->viMediaThd, NULL, VI_MediaHdmiThd, pViCtl);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
        goto free_ctl;
    }
    
#endif
    
#if 0
    /* FIXME */
    if( 0 == pViDesc->channel )
    {
        pViCtl->emViStream  = videoViStreamMain;
        pViCtl->iEnable     = 1;
    }
    else if(1 == pViDesc->channel)
    {
        pViCtl->emViStream  = videoViStreamExtra1;
        pViCtl->iEnable     = 0;
    }

    /* config and enable vi */
    ret = VI_EnableViMod(pViCtl);
    if(ret)
    {
        LOG_PrintError("ENC_EnableViMod failed, iRet:%d\n",ret);
        ret = -1;
        goto mutex_unlock;
    }

    for(int i=0;i<VIDEO_STREAM_MAX_CHN_NUMBER;i++)
    {
        StreamExt_ctl_t *pstStreamCtl = &(videoCtl_g.stStreamExtCtrl[i]);
        pstStreamCtl->iEnable = 0;
    }

    pthread_mutex_init(&(pViCtl->viChnMutex), NULL);
    pthread_mutex_init(&(pViCtl->viSecChnMutex), NULL);


    if(videoViStreamExtra1 == pViCtl->emViStream)
    {
        videoCtl_g.iPipStatus = 0;
        /* init list */
        StreamExt_ctl_t* pstStreamExtCtrl = NULL;
        int chn = VIDEO_STREAM_FIXED_SENSOR_PIP_LIST_CHN;
        pstStreamExtCtrl = &(videoCtl_g.stStreamExtCtrl[chn]);
        ENC_ImageBufInfo_t stImageInfo;

        stImageInfo.stRect.wid = VIDEO_STREAM_FIXED_SENSOR_PIP_WID;
        stImageInfo.stRect.hei = VIDEO_STREAM_FIXED_SENSOR_PIP_HEI;

        pstStreamExtCtrl->iChnId = chn;

        Stream_ListInit(chn,stImageInfo);

        pstStreamExtCtrl->iEnable = 1;


        ret = pthread_create(&pViCtl->viMediaSecThd, NULL, VI_MediaSecThd, pViCtl);
        if (ret)
        {
            LOG_PrintError("can't create thread: %s\n", strerror(ret));
            ret = -1;
            goto mutex_unlock;
        }
    }

    /* get vi stream buffer */
    ret = pthread_create(&pViCtl->viMediaThd, NULL, VI_MediaThd, pViCtl);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
        goto mutex_unlock;
    }

    pViCtl->iMenuOsdShow = 0;
    ENC_AlgOsdBufferInit(1920,1080,0);
#endif

    pVideoInput                             = &pViCtl->videoInput;
    pVideoInput->priv                       = pViCtl;
    pVideoInput->addRef                     = VI_AddRef;
    pVideoInput->release                    = VI_Release;
    pVideoInput->enableAutoIris             = VI_EnableAutoIris;
    pVideoInput->getCaps                    = VI_GetCaps;
    pVideoInput->getExposureSpeeds          = VI_GetExposureSpeeds;
    pVideoInput->getFormatCaps              = VI_GetFormatCaps;
    pVideoInput->getFormatCapsEx            = VI_GetFormatCapsEx;
    pVideoInput->setColor                   = VI_SetColor;
    pVideoInput->setOptions                 = VI_SetOptions;
    pVideoInput->setPreviewOptions          = VI_SetPreviewOptions;
    pVideoInput->setStandard                = VI_SetStandard;
    pVideoInput->setFormat                  = VI_SetFormat;
	pVideoInput->adjustFocus		        = VI_AdjustFocus;
	pVideoInput->adjustFocusContinuously	= VI_AdjustFocusContinuously;
	pVideoInput->adjustIris			        = VI_AdjustIris;
	pVideoInput->autoFocus			        = VI_AutoFocus;
	pVideoInput->getFocusStatus		        = VI_GetFocusStatus;
	pVideoInput->setFocus                   = VI_SetFocus;
	pVideoInput->setZoom                    = VI_SetZoom;
	pVideoInput->getStatus			        = VI_GetStatus;
	pVideoInput->getVideoInPutStatus	    = VI_GetVideoInPutStatus;
	pVideoInput->reset				        = VI_Reset;
	pVideoInput->savePreviewOptions	        = VI_SavePreviewOptions;
	pVideoInput->setBackgroundColor	        = VI_SetBackgroundColor;
	pVideoInput->setColorAdjustArea	        = VI_SetColorAdjustArea;
	pVideoInput->setCover			        = VI_SetCover;
	pVideoInput->setDenoise		            = VI_SetDenoise;
	pVideoInput->setDenoiseParamsMaps	    = VI_SetDenoiseParamsMaps;
	pVideoInput->setFocusMode		        = VI_SetFocusMode;
	pVideoInput->setKillHalo			    = VI_SetKillHalo;
	pVideoInput->setMeteringMode	        = VI_SetMeteringMode;
	pVideoInput->setMode			        = VI_SetMode;
	pVideoInput->setMonitorMode	            = VI_SetMonitorMode;
	pVideoInput->setSensorOptions	        = VI_SetSensorOptions;
	pVideoInput->setSensorType		        = VI_SetSensorType;
	pVideoInput->setSyncPhase		        = VI_SetSyncPhase;
	pVideoInput->setTitle			        = VI_SetTitle;
	pVideoInput->setWidgetLine		        = VI_SetWidgetLine;
	pVideoInput->snapshot			        = VI_Snapshot;
	pVideoInput->setSmartIr                 = VI_SetSmartIr;
	pVideoInput->setAutoIris                = VI_SetAutoIris;
	pVideoInput->setWhiteBalance            = VI_SetWhiteBalance;
	pVideoInput->setLDC                     = VI_SetLdc;
	pVideoInput->setLdr                     = VI_SetLdr;
    pVideoInput->setFec                     = VI_SetFec;
    pVideoInput->ctrltPtz                   = VI_CtrltPtz;
	pVideoInput->getFocusLimit              = VI_GetFocusLimit;
	pVideoInput->setIris                    = VI_SetIris;
	pVideoInput->setDis                     = VI_SetDis;
	pVideoInput->getColor                   = VI_GetColor;
    pVideoInput->getOptions                 = VI_GetOptions;
    pVideoInput->enableViStream             = VI_EnableViStream;
    pVideoInput->setViCrop                  = VI_SetCrop;
    pVideoInput->getViCrop                  = VI_GetCrop;
    pVideoInput->setPipStatus               = VI_SetPicInPicStatus;
    pVideoInput->setAiMode                  = VI_SetAiMode;
    pVideoInput->setPipRoiCfg               = VI_SetRoiCfg;

    *ppVideoInput = &pViCtl->videoInput;

    LOG_PrintInfo("Create pViDesc->channel:%d successfully!\n",pViDesc->channel);
    goto mutex_unlock;


free_ctl: 
    free(pViCtl);
    
mutex_unlock:
    pthread_mutex_unlock(&videoCtl_g.viMutex);
    return ret;
}

/*******************************************************************************
  Function:     getVideoInputChannels
  Description:  得到视频输入通道的个数
  Input:        无
  Output:       无
  Return:       输入通道的个数
  Others:       无
*******************************************************************************/
int PAL_API getVideoInputChannels(void)
{
    return videoCtl_g.viChnNum;
}

/*******************************************************************************
  Function:     getVideoInputStandardMask
  Description:  得到视频输入支持的制式标准
  Input:        无
  Output:       - pstandartdMask: 视频输入制式掩码指针，
                  取 VideoStandard 的位掩码
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int PAL_API getVideoInputStandardMask(int *pstandartdMask)
{
    *pstandartdMask = (1 << videoStandardPAL) | (1 << videoStandardNTSC);
    return 0;
}

/*******************************************************************************
  Function:     setVideoInputMode
  Description:  设置视频输入码流模式，确定模拟的视频输入通道数
  Input:        无
  Output:       - pstandartdMask: 视频输入制式掩码指针，
                  取 VideoStandard 的位掩码
  Return:       0: 操作成功
                -1: 操作失败
  Others:       无
*******************************************************************************/
int PAL_API setVideoInputMode(VideoInputMode mode)
{
	videoCtl_g.viChnNum = 1;
    videoCtl_g.viMode = VIDEOIN_ORIGINAL;
    return 0;
}


